root/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dm_helpers_parse_edid_caps
  2. get_payload_table
  3. dm_helpers_dp_update_branch_info
  4. dm_helpers_dp_mst_write_payload_allocation_table
  5. dm_helpers_dp_mst_poll_pending_down_reply
  6. dm_helpers_dp_mst_clear_payload_allocation_table
  7. dm_helpers_dp_mst_poll_for_allocation_change_trigger
  8. dm_helpers_dp_mst_send_payload_allocation
  9. dm_dtn_log_begin
  10. dm_dtn_log_append_v
  11. dm_dtn_log_end
  12. dm_helpers_dp_mst_start_top_mgr
  13. dm_helpers_dp_mst_stop_top_mgr
  14. dm_helpers_dp_read_dpcd
  15. dm_helpers_dp_write_dpcd
  16. dm_helpers_submit_i2c
  17. dm_helpers_dp_write_dsc_enable
  18. dm_helpers_is_dp_sink_present
  19. dm_helpers_read_local_edid
  20. dm_set_dcn_clocks

   1 /*
   2  * Copyright 2015 Advanced Micro Devices, Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  * Authors: AMD
  23  *
  24  */
  25 
  26 #include <linux/string.h>
  27 #include <linux/acpi.h>
  28 #include <linux/version.h>
  29 #include <linux/i2c.h>
  30 
  31 #include <drm/drm_probe_helper.h>
  32 #include <drm/amdgpu_drm.h>
  33 #include <drm/drm_edid.h>
  34 
  35 #include "dm_services.h"
  36 #include "amdgpu.h"
  37 #include "dc.h"
  38 #include "amdgpu_dm.h"
  39 #include "amdgpu_dm_irq.h"
  40 
  41 #include "dm_helpers.h"
  42 
  43 /* dm_helpers_parse_edid_caps
  44  *
  45  * Parse edid caps
  46  *
  47  * @edid:       [in] pointer to edid
  48  *  edid_caps:  [in] pointer to edid caps
  49  * @return
  50  *      void
  51  * */
  52 enum dc_edid_status dm_helpers_parse_edid_caps(
  53                 struct dc_context *ctx,
  54                 const struct dc_edid *edid,
  55                 struct dc_edid_caps *edid_caps)
  56 {
  57         struct edid *edid_buf = (struct edid *) edid->raw_edid;
  58         struct cea_sad *sads;
  59         int sad_count = -1;
  60         int sadb_count = -1;
  61         int i = 0;
  62         int j = 0;
  63         uint8_t *sadb = NULL;
  64 
  65         enum dc_edid_status result = EDID_OK;
  66 
  67         if (!edid_caps || !edid)
  68                 return EDID_BAD_INPUT;
  69 
  70         if (!drm_edid_is_valid(edid_buf))
  71                 result = EDID_BAD_CHECKSUM;
  72 
  73         edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
  74                                         ((uint16_t) edid_buf->mfg_id[1])<<8;
  75         edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
  76                                         ((uint16_t) edid_buf->prod_code[1])<<8;
  77         edid_caps->serial_number = edid_buf->serial;
  78         edid_caps->manufacture_week = edid_buf->mfg_week;
  79         edid_caps->manufacture_year = edid_buf->mfg_year;
  80 
  81         /* One of the four detailed_timings stores the monitor name. It's
  82          * stored in an array of length 13. */
  83         for (i = 0; i < 4; i++) {
  84                 if (edid_buf->detailed_timings[i].data.other_data.type == 0xfc) {
  85                         while (j < 13 && edid_buf->detailed_timings[i].data.other_data.data.str.str[j]) {
  86                                 if (edid_buf->detailed_timings[i].data.other_data.data.str.str[j] == '\n')
  87                                         break;
  88 
  89                                 edid_caps->display_name[j] =
  90                                         edid_buf->detailed_timings[i].data.other_data.data.str.str[j];
  91                                 j++;
  92                         }
  93                 }
  94         }
  95 
  96         edid_caps->edid_hdmi = drm_detect_hdmi_monitor(
  97                         (struct edid *) edid->raw_edid);
  98 
  99         sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
 100         if (sad_count <= 0) {
 101                 DRM_INFO("SADs count is: %d, don't need to read it\n",
 102                                 sad_count);
 103                 return result;
 104         }
 105 
 106         edid_caps->audio_mode_count = sad_count < DC_MAX_AUDIO_DESC_COUNT ? sad_count : DC_MAX_AUDIO_DESC_COUNT;
 107         for (i = 0; i < edid_caps->audio_mode_count; ++i) {
 108                 struct cea_sad *sad = &sads[i];
 109 
 110                 edid_caps->audio_modes[i].format_code = sad->format;
 111                 edid_caps->audio_modes[i].channel_count = sad->channels + 1;
 112                 edid_caps->audio_modes[i].sample_rate = sad->freq;
 113                 edid_caps->audio_modes[i].sample_size = sad->byte2;
 114         }
 115 
 116         sadb_count = drm_edid_to_speaker_allocation((struct edid *) edid->raw_edid, &sadb);
 117 
 118         if (sadb_count < 0) {
 119                 DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count);
 120                 sadb_count = 0;
 121         }
 122 
 123         if (sadb_count)
 124                 edid_caps->speaker_flags = sadb[0];
 125         else
 126                 edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 127 
 128         kfree(sads);
 129         kfree(sadb);
 130 
 131         return result;
 132 }
 133 
 134 static void get_payload_table(
 135                 struct amdgpu_dm_connector *aconnector,
 136                 struct dp_mst_stream_allocation_table *proposed_table)
 137 {
 138         int i;
 139         struct drm_dp_mst_topology_mgr *mst_mgr =
 140                         &aconnector->mst_port->mst_mgr;
 141 
 142         mutex_lock(&mst_mgr->payload_lock);
 143 
 144         proposed_table->stream_count = 0;
 145 
 146         /* number of active streams */
 147         for (i = 0; i < mst_mgr->max_payloads; i++) {
 148                 if (mst_mgr->payloads[i].num_slots == 0)
 149                         break; /* end of vcp_id table */
 150 
 151                 ASSERT(mst_mgr->payloads[i].payload_state !=
 152                                 DP_PAYLOAD_DELETE_LOCAL);
 153 
 154                 if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL ||
 155                         mst_mgr->payloads[i].payload_state ==
 156                                         DP_PAYLOAD_REMOTE) {
 157 
 158                         struct dp_mst_stream_allocation *sa =
 159                                         &proposed_table->stream_allocations[
 160                                                 proposed_table->stream_count];
 161 
 162                         sa->slot_count = mst_mgr->payloads[i].num_slots;
 163                         sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi;
 164                         proposed_table->stream_count++;
 165                 }
 166         }
 167 
 168         mutex_unlock(&mst_mgr->payload_lock);
 169 }
 170 
 171 void dm_helpers_dp_update_branch_info(
 172         struct dc_context *ctx,
 173         const struct dc_link *link)
 174 {}
 175 
 176 /*
 177  * Writes payload allocation table in immediate downstream device.
 178  */
 179 bool dm_helpers_dp_mst_write_payload_allocation_table(
 180                 struct dc_context *ctx,
 181                 const struct dc_stream_state *stream,
 182                 struct dp_mst_stream_allocation_table *proposed_table,
 183                 bool enable)
 184 {
 185         struct amdgpu_dm_connector *aconnector;
 186         struct drm_dp_mst_topology_mgr *mst_mgr;
 187         struct drm_dp_mst_port *mst_port;
 188         int slots = 0;
 189         bool ret;
 190         int clock;
 191         int bpp = 0;
 192         int pbn = 0;
 193 
 194         aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 195 
 196         if (!aconnector || !aconnector->mst_port)
 197                 return false;
 198 
 199         mst_mgr = &aconnector->mst_port->mst_mgr;
 200 
 201         if (!mst_mgr->mst_state)
 202                 return false;
 203 
 204         mst_port = aconnector->port;
 205 
 206         if (enable) {
 207                 clock = stream->timing.pix_clk_100hz / 10;
 208 
 209                 switch (stream->timing.display_color_depth) {
 210 
 211                 case COLOR_DEPTH_666:
 212                         bpp = 6;
 213                         break;
 214                 case COLOR_DEPTH_888:
 215                         bpp = 8;
 216                         break;
 217                 case COLOR_DEPTH_101010:
 218                         bpp = 10;
 219                         break;
 220                 case COLOR_DEPTH_121212:
 221                         bpp = 12;
 222                         break;
 223                 case COLOR_DEPTH_141414:
 224                         bpp = 14;
 225                         break;
 226                 case COLOR_DEPTH_161616:
 227                         bpp = 16;
 228                         break;
 229                 default:
 230                         ASSERT(bpp != 0);
 231                         break;
 232                 }
 233 
 234                 bpp = bpp * 3;
 235 
 236                 /* TODO need to know link rate */
 237 
 238                 pbn = drm_dp_calc_pbn_mode(clock, bpp);
 239 
 240                 slots = drm_dp_find_vcpi_slots(mst_mgr, pbn);
 241                 ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, pbn, slots);
 242 
 243                 if (!ret)
 244                         return false;
 245 
 246         } else {
 247                 drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
 248         }
 249 
 250         /* It's OK for this to fail */
 251         drm_dp_update_payload_part1(mst_mgr);
 252 
 253         /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
 254          * AUX message. The sequence is slot 1-63 allocated sequence for each
 255          * stream. AMD ASIC stream slot allocation should follow the same
 256          * sequence. copy DRM MST allocation to dc */
 257 
 258         get_payload_table(aconnector, proposed_table);
 259 
 260         return true;
 261 }
 262 
 263 /*
 264  * poll pending down reply
 265  */
 266 void dm_helpers_dp_mst_poll_pending_down_reply(
 267         struct dc_context *ctx,
 268         const struct dc_link *link)
 269 {}
 270 
 271 /*
 272  * Clear payload allocation table before enable MST DP link.
 273  */
 274 void dm_helpers_dp_mst_clear_payload_allocation_table(
 275         struct dc_context *ctx,
 276         const struct dc_link *link)
 277 {}
 278 
 279 /*
 280  * Polls for ACT (allocation change trigger) handled and sends
 281  * ALLOCATE_PAYLOAD message.
 282  */
 283 bool dm_helpers_dp_mst_poll_for_allocation_change_trigger(
 284                 struct dc_context *ctx,
 285                 const struct dc_stream_state *stream)
 286 {
 287         struct amdgpu_dm_connector *aconnector;
 288         struct drm_dp_mst_topology_mgr *mst_mgr;
 289         int ret;
 290 
 291         aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 292 
 293         if (!aconnector || !aconnector->mst_port)
 294                 return false;
 295 
 296         mst_mgr = &aconnector->mst_port->mst_mgr;
 297 
 298         if (!mst_mgr->mst_state)
 299                 return false;
 300 
 301         ret = drm_dp_check_act_status(mst_mgr);
 302 
 303         if (ret)
 304                 return false;
 305 
 306         return true;
 307 }
 308 
 309 bool dm_helpers_dp_mst_send_payload_allocation(
 310                 struct dc_context *ctx,
 311                 const struct dc_stream_state *stream,
 312                 bool enable)
 313 {
 314         struct amdgpu_dm_connector *aconnector;
 315         struct drm_dp_mst_topology_mgr *mst_mgr;
 316         struct drm_dp_mst_port *mst_port;
 317 
 318         aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 319 
 320         if (!aconnector || !aconnector->mst_port)
 321                 return false;
 322 
 323         mst_port = aconnector->port;
 324 
 325         mst_mgr = &aconnector->mst_port->mst_mgr;
 326 
 327         if (!mst_mgr->mst_state)
 328                 return false;
 329 
 330         /* It's OK for this to fail */
 331         drm_dp_update_payload_part2(mst_mgr);
 332 
 333         if (!enable)
 334                 drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
 335 
 336         return true;
 337 }
 338 
 339 void dm_dtn_log_begin(struct dc_context *ctx,
 340         struct dc_log_buffer_ctx *log_ctx)
 341 {
 342         static const char msg[] = "[dtn begin]\n";
 343 
 344         if (!log_ctx) {
 345                 pr_info("%s", msg);
 346                 return;
 347         }
 348 
 349         dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
 350 }
 351 
 352 void dm_dtn_log_append_v(struct dc_context *ctx,
 353         struct dc_log_buffer_ctx *log_ctx,
 354         const char *msg, ...)
 355 {
 356         va_list args;
 357         size_t total;
 358         int n;
 359 
 360         if (!log_ctx) {
 361                 /* No context, redirect to dmesg. */
 362                 struct va_format vaf;
 363 
 364                 vaf.fmt = msg;
 365                 vaf.va = &args;
 366 
 367                 va_start(args, msg);
 368                 pr_info("%pV", &vaf);
 369                 va_end(args);
 370 
 371                 return;
 372         }
 373 
 374         /* Measure the output. */
 375         va_start(args, msg);
 376         n = vsnprintf(NULL, 0, msg, args);
 377         va_end(args);
 378 
 379         if (n <= 0)
 380                 return;
 381 
 382         /* Reallocate the string buffer as needed. */
 383         total = log_ctx->pos + n + 1;
 384 
 385         if (total > log_ctx->size) {
 386                 char *buf = (char *)kvcalloc(total, sizeof(char), GFP_KERNEL);
 387 
 388                 if (buf) {
 389                         memcpy(buf, log_ctx->buf, log_ctx->pos);
 390                         kfree(log_ctx->buf);
 391 
 392                         log_ctx->buf = buf;
 393                         log_ctx->size = total;
 394                 }
 395         }
 396 
 397         if (!log_ctx->buf)
 398                 return;
 399 
 400         /* Write the formatted string to the log buffer. */
 401         va_start(args, msg);
 402         n = vscnprintf(
 403                 log_ctx->buf + log_ctx->pos,
 404                 log_ctx->size - log_ctx->pos,
 405                 msg,
 406                 args);
 407         va_end(args);
 408 
 409         if (n > 0)
 410                 log_ctx->pos += n;
 411 }
 412 
 413 void dm_dtn_log_end(struct dc_context *ctx,
 414         struct dc_log_buffer_ctx *log_ctx)
 415 {
 416         static const char msg[] = "[dtn end]\n";
 417 
 418         if (!log_ctx) {
 419                 pr_info("%s", msg);
 420                 return;
 421         }
 422 
 423         dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
 424 }
 425 
 426 bool dm_helpers_dp_mst_start_top_mgr(
 427                 struct dc_context *ctx,
 428                 const struct dc_link *link,
 429                 bool boot)
 430 {
 431         struct amdgpu_dm_connector *aconnector = link->priv;
 432 
 433         if (!aconnector) {
 434                         DRM_ERROR("Failed to found connector for link!");
 435                         return false;
 436         }
 437 
 438         if (boot) {
 439                 DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
 440                                         aconnector, aconnector->base.base.id);
 441                 return true;
 442         }
 443 
 444         DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
 445                         aconnector, aconnector->base.base.id);
 446 
 447         return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
 448 }
 449 
 450 void dm_helpers_dp_mst_stop_top_mgr(
 451                 struct dc_context *ctx,
 452                 const struct dc_link *link)
 453 {
 454         struct amdgpu_dm_connector *aconnector = link->priv;
 455 
 456         if (!aconnector) {
 457                         DRM_ERROR("Failed to found connector for link!");
 458                         return;
 459         }
 460 
 461         DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
 462                         aconnector, aconnector->base.base.id);
 463 
 464         if (aconnector->mst_mgr.mst_state == true)
 465                 drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, false);
 466 }
 467 
 468 bool dm_helpers_dp_read_dpcd(
 469                 struct dc_context *ctx,
 470                 const struct dc_link *link,
 471                 uint32_t address,
 472                 uint8_t *data,
 473                 uint32_t size)
 474 {
 475 
 476         struct amdgpu_dm_connector *aconnector = link->priv;
 477 
 478         if (!aconnector) {
 479                 DRM_ERROR("Failed to found connector for link!");
 480                 return false;
 481         }
 482 
 483         return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address,
 484                         data, size) > 0;
 485 }
 486 
 487 bool dm_helpers_dp_write_dpcd(
 488                 struct dc_context *ctx,
 489                 const struct dc_link *link,
 490                 uint32_t address,
 491                 const uint8_t *data,
 492                 uint32_t size)
 493 {
 494         struct amdgpu_dm_connector *aconnector = link->priv;
 495 
 496         if (!aconnector) {
 497                 DRM_ERROR("Failed to found connector for link!");
 498                 return false;
 499         }
 500 
 501         return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux,
 502                         address, (uint8_t *)data, size) > 0;
 503 }
 504 
 505 bool dm_helpers_submit_i2c(
 506                 struct dc_context *ctx,
 507                 const struct dc_link *link,
 508                 struct i2c_command *cmd)
 509 {
 510         struct amdgpu_dm_connector *aconnector = link->priv;
 511         struct i2c_msg *msgs;
 512         int i = 0;
 513         int num = cmd->number_of_payloads;
 514         bool result;
 515 
 516         if (!aconnector) {
 517                 DRM_ERROR("Failed to found connector for link!");
 518                 return false;
 519         }
 520 
 521         msgs = kcalloc(num, sizeof(struct i2c_msg), GFP_KERNEL);
 522 
 523         if (!msgs)
 524                 return false;
 525 
 526         for (i = 0; i < num; i++) {
 527                 msgs[i].flags = cmd->payloads[i].write ? 0 : I2C_M_RD;
 528                 msgs[i].addr = cmd->payloads[i].address;
 529                 msgs[i].len = cmd->payloads[i].length;
 530                 msgs[i].buf = cmd->payloads[i].data;
 531         }
 532 
 533         result = i2c_transfer(&aconnector->i2c->base, msgs, num) == num;
 534 
 535         kfree(msgs);
 536 
 537         return result;
 538 }
 539 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
 540 bool dm_helpers_dp_write_dsc_enable(
 541                 struct dc_context *ctx,
 542                 const struct dc_stream_state *stream,
 543                 bool enable
 544 )
 545 {
 546         uint8_t enable_dsc = enable ? 1 : 0;
 547 
 548         return dm_helpers_dp_write_dpcd(ctx, stream->sink->link, DP_DSC_ENABLE, &enable_dsc, 1);
 549 }
 550 #endif
 551 
 552 bool dm_helpers_is_dp_sink_present(struct dc_link *link)
 553 {
 554         bool dp_sink_present;
 555         struct amdgpu_dm_connector *aconnector = link->priv;
 556 
 557         if (!aconnector) {
 558                 BUG_ON("Failed to found connector for link!");
 559                 return true;
 560         }
 561 
 562         mutex_lock(&aconnector->dm_dp_aux.aux.hw_mutex);
 563         dp_sink_present = dc_link_is_dp_sink_present(link);
 564         mutex_unlock(&aconnector->dm_dp_aux.aux.hw_mutex);
 565         return dp_sink_present;
 566 }
 567 
 568 enum dc_edid_status dm_helpers_read_local_edid(
 569                 struct dc_context *ctx,
 570                 struct dc_link *link,
 571                 struct dc_sink *sink)
 572 {
 573         struct amdgpu_dm_connector *aconnector = link->priv;
 574         struct i2c_adapter *ddc;
 575         int retry = 3;
 576         enum dc_edid_status edid_status;
 577         struct edid *edid;
 578 
 579         if (link->aux_mode)
 580                 ddc = &aconnector->dm_dp_aux.aux.ddc;
 581         else
 582                 ddc = &aconnector->i2c->base;
 583 
 584         /* some dongles read edid incorrectly the first time,
 585          * do check sum and retry to make sure read correct edid.
 586          */
 587         do {
 588 
 589                 edid = drm_get_edid(&aconnector->base, ddc);
 590 
 591                 if (!edid)
 592                         return EDID_NO_RESPONSE;
 593 
 594                 sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
 595                 memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
 596 
 597                 /* We don't need the original edid anymore */
 598                 kfree(edid);
 599 
 600                 edid_status = dm_helpers_parse_edid_caps(
 601                                                 ctx,
 602                                                 &sink->dc_edid,
 603                                                 &sink->edid_caps);
 604 
 605         } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
 606 
 607         if (edid_status != EDID_OK)
 608                 DRM_ERROR("EDID err: %d, on connector: %s",
 609                                 edid_status,
 610                                 aconnector->base.name);
 611         if (link->aux_mode) {
 612                 union test_request test_request = { {0} };
 613                 union test_response test_response = { {0} };
 614 
 615                 dm_helpers_dp_read_dpcd(ctx,
 616                                         link,
 617                                         DP_TEST_REQUEST,
 618                                         &test_request.raw,
 619                                         sizeof(union test_request));
 620 
 621                 if (!test_request.bits.EDID_READ)
 622                         return edid_status;
 623 
 624                 test_response.bits.EDID_CHECKSUM_WRITE = 1;
 625 
 626                 dm_helpers_dp_write_dpcd(ctx,
 627                                         link,
 628                                         DP_TEST_EDID_CHECKSUM,
 629                                         &sink->dc_edid.raw_edid[sink->dc_edid.length-1],
 630                                         1);
 631 
 632                 dm_helpers_dp_write_dpcd(ctx,
 633                                         link,
 634                                         DP_TEST_RESPONSE,
 635                                         &test_response.raw,
 636                                         sizeof(test_response));
 637 
 638         }
 639 
 640         return edid_status;
 641 }
 642 
 643 void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks)
 644 {
 645         /* TODO: something */
 646 }

/* [<][>][^][v][top][bottom][index][help] */