linux/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
<<
>>
Prefs
   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/i2c.h>
  29
  30#include <drm/drm_probe_helper.h>
  31#include <drm/amdgpu_drm.h>
  32#include <drm/drm_edid.h>
  33
  34#include "dm_services.h"
  35#include "amdgpu.h"
  36#include "dc.h"
  37#include "amdgpu_dm.h"
  38#include "amdgpu_dm_irq.h"
  39#include "amdgpu_dm_mst_types.h"
  40
  41#include "dm_helpers.h"
  42
  43struct monitor_patch_info {
  44        unsigned int manufacturer_id;
  45        unsigned int product_id;
  46        void (*patch_func)(struct dc_edid_caps *edid_caps, unsigned int param);
  47        unsigned int patch_param;
  48};
  49static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param);
  50
  51static const struct monitor_patch_info monitor_patch_table[] = {
  52{0x6D1E, 0x5BBF, set_max_dsc_bpp_limit, 15},
  53{0x6D1E, 0x5B9A, set_max_dsc_bpp_limit, 15},
  54};
  55
  56static void set_max_dsc_bpp_limit(struct dc_edid_caps *edid_caps, unsigned int param)
  57{
  58        if (edid_caps)
  59                edid_caps->panel_patch.max_dsc_target_bpp_limit = param;
  60}
  61
  62static int amdgpu_dm_patch_edid_caps(struct dc_edid_caps *edid_caps)
  63{
  64        int i, ret = 0;
  65
  66        for (i = 0; i < ARRAY_SIZE(monitor_patch_table); i++)
  67                if ((edid_caps->manufacturer_id == monitor_patch_table[i].manufacturer_id)
  68                        &&  (edid_caps->product_id == monitor_patch_table[i].product_id)) {
  69                        monitor_patch_table[i].patch_func(edid_caps, monitor_patch_table[i].patch_param);
  70                        ret++;
  71                }
  72
  73        return ret;
  74}
  75
  76/* dm_helpers_parse_edid_caps
  77 *
  78 * Parse edid caps
  79 *
  80 * @edid:       [in] pointer to edid
  81 *  edid_caps:  [in] pointer to edid caps
  82 * @return
  83 *      void
  84 * */
  85enum dc_edid_status dm_helpers_parse_edid_caps(
  86                struct dc_context *ctx,
  87                const struct dc_edid *edid,
  88                struct dc_edid_caps *edid_caps)
  89{
  90        struct edid *edid_buf = (struct edid *) edid->raw_edid;
  91        struct cea_sad *sads;
  92        int sad_count = -1;
  93        int sadb_count = -1;
  94        int i = 0;
  95        int j = 0;
  96        uint8_t *sadb = NULL;
  97
  98        enum dc_edid_status result = EDID_OK;
  99
 100        if (!edid_caps || !edid)
 101                return EDID_BAD_INPUT;
 102
 103        if (!drm_edid_is_valid(edid_buf))
 104                result = EDID_BAD_CHECKSUM;
 105
 106        edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
 107                                        ((uint16_t) edid_buf->mfg_id[1])<<8;
 108        edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
 109                                        ((uint16_t) edid_buf->prod_code[1])<<8;
 110        edid_caps->serial_number = edid_buf->serial;
 111        edid_caps->manufacture_week = edid_buf->mfg_week;
 112        edid_caps->manufacture_year = edid_buf->mfg_year;
 113
 114        /* One of the four detailed_timings stores the monitor name. It's
 115         * stored in an array of length 13. */
 116        for (i = 0; i < 4; i++) {
 117                if (edid_buf->detailed_timings[i].data.other_data.type == 0xfc) {
 118                        while (j < 13 && edid_buf->detailed_timings[i].data.other_data.data.str.str[j]) {
 119                                if (edid_buf->detailed_timings[i].data.other_data.data.str.str[j] == '\n')
 120                                        break;
 121
 122                                edid_caps->display_name[j] =
 123                                        edid_buf->detailed_timings[i].data.other_data.data.str.str[j];
 124                                j++;
 125                        }
 126                }
 127        }
 128
 129        edid_caps->edid_hdmi = drm_detect_hdmi_monitor(
 130                        (struct edid *) edid->raw_edid);
 131
 132        sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
 133        if (sad_count <= 0)
 134                return result;
 135
 136        edid_caps->audio_mode_count = sad_count < DC_MAX_AUDIO_DESC_COUNT ? sad_count : DC_MAX_AUDIO_DESC_COUNT;
 137        for (i = 0; i < edid_caps->audio_mode_count; ++i) {
 138                struct cea_sad *sad = &sads[i];
 139
 140                edid_caps->audio_modes[i].format_code = sad->format;
 141                edid_caps->audio_modes[i].channel_count = sad->channels + 1;
 142                edid_caps->audio_modes[i].sample_rate = sad->freq;
 143                edid_caps->audio_modes[i].sample_size = sad->byte2;
 144        }
 145
 146        sadb_count = drm_edid_to_speaker_allocation((struct edid *) edid->raw_edid, &sadb);
 147
 148        if (sadb_count < 0) {
 149                DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count);
 150                sadb_count = 0;
 151        }
 152
 153        if (sadb_count)
 154                edid_caps->speaker_flags = sadb[0];
 155        else
 156                edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
 157
 158        kfree(sads);
 159        kfree(sadb);
 160
 161        amdgpu_dm_patch_edid_caps(edid_caps);
 162
 163        return result;
 164}
 165
 166static void get_payload_table(
 167                struct amdgpu_dm_connector *aconnector,
 168                struct dp_mst_stream_allocation_table *proposed_table)
 169{
 170        int i;
 171        struct drm_dp_mst_topology_mgr *mst_mgr =
 172                        &aconnector->mst_port->mst_mgr;
 173
 174        mutex_lock(&mst_mgr->payload_lock);
 175
 176        proposed_table->stream_count = 0;
 177
 178        /* number of active streams */
 179        for (i = 0; i < mst_mgr->max_payloads; i++) {
 180                if (mst_mgr->payloads[i].num_slots == 0)
 181                        break; /* end of vcp_id table */
 182
 183                ASSERT(mst_mgr->payloads[i].payload_state !=
 184                                DP_PAYLOAD_DELETE_LOCAL);
 185
 186                if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL ||
 187                        mst_mgr->payloads[i].payload_state ==
 188                                        DP_PAYLOAD_REMOTE) {
 189
 190                        struct dp_mst_stream_allocation *sa =
 191                                        &proposed_table->stream_allocations[
 192                                                proposed_table->stream_count];
 193
 194                        sa->slot_count = mst_mgr->payloads[i].num_slots;
 195                        sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi;
 196                        proposed_table->stream_count++;
 197                }
 198        }
 199
 200        mutex_unlock(&mst_mgr->payload_lock);
 201}
 202
 203void dm_helpers_dp_update_branch_info(
 204        struct dc_context *ctx,
 205        const struct dc_link *link)
 206{}
 207
 208/*
 209 * Writes payload allocation table in immediate downstream device.
 210 */
 211bool dm_helpers_dp_mst_write_payload_allocation_table(
 212                struct dc_context *ctx,
 213                const struct dc_stream_state *stream,
 214                struct dp_mst_stream_allocation_table *proposed_table,
 215                bool enable)
 216{
 217        struct amdgpu_dm_connector *aconnector;
 218        struct dm_connector_state *dm_conn_state;
 219        struct drm_dp_mst_topology_mgr *mst_mgr;
 220        struct drm_dp_mst_port *mst_port;
 221        bool ret;
 222
 223        aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 224        /* Accessing the connector state is required for vcpi_slots allocation
 225         * and directly relies on behaviour in commit check
 226         * that blocks before commit guaranteeing that the state
 227         * is not gonna be swapped while still in use in commit tail */
 228
 229        if (!aconnector || !aconnector->mst_port)
 230                return false;
 231
 232        dm_conn_state = to_dm_connector_state(aconnector->base.state);
 233
 234        mst_mgr = &aconnector->mst_port->mst_mgr;
 235
 236        if (!mst_mgr->mst_state)
 237                return false;
 238
 239        mst_port = aconnector->port;
 240
 241        if (enable) {
 242
 243                ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port,
 244                                               dm_conn_state->pbn,
 245                                               dm_conn_state->vcpi_slots);
 246                if (!ret)
 247                        return false;
 248
 249        } else {
 250                drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
 251        }
 252
 253        /* It's OK for this to fail */
 254        drm_dp_update_payload_part1(mst_mgr);
 255
 256        /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
 257         * AUX message. The sequence is slot 1-63 allocated sequence for each
 258         * stream. AMD ASIC stream slot allocation should follow the same
 259         * sequence. copy DRM MST allocation to dc */
 260
 261        get_payload_table(aconnector, proposed_table);
 262
 263        return true;
 264}
 265
 266/*
 267 * poll pending down reply
 268 */
 269void dm_helpers_dp_mst_poll_pending_down_reply(
 270        struct dc_context *ctx,
 271        const struct dc_link *link)
 272{}
 273
 274/*
 275 * Clear payload allocation table before enable MST DP link.
 276 */
 277void dm_helpers_dp_mst_clear_payload_allocation_table(
 278        struct dc_context *ctx,
 279        const struct dc_link *link)
 280{}
 281
 282/*
 283 * Polls for ACT (allocation change trigger) handled and sends
 284 * ALLOCATE_PAYLOAD message.
 285 */
 286enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger(
 287                struct dc_context *ctx,
 288                const struct dc_stream_state *stream)
 289{
 290        struct amdgpu_dm_connector *aconnector;
 291        struct drm_dp_mst_topology_mgr *mst_mgr;
 292        int ret;
 293
 294        aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 295
 296        if (!aconnector || !aconnector->mst_port)
 297                return ACT_FAILED;
 298
 299        mst_mgr = &aconnector->mst_port->mst_mgr;
 300
 301        if (!mst_mgr->mst_state)
 302                return ACT_FAILED;
 303
 304        ret = drm_dp_check_act_status(mst_mgr);
 305
 306        if (ret)
 307                return ACT_FAILED;
 308
 309        return ACT_SUCCESS;
 310}
 311
 312bool dm_helpers_dp_mst_send_payload_allocation(
 313                struct dc_context *ctx,
 314                const struct dc_stream_state *stream,
 315                bool enable)
 316{
 317        struct amdgpu_dm_connector *aconnector;
 318        struct drm_dp_mst_topology_mgr *mst_mgr;
 319        struct drm_dp_mst_port *mst_port;
 320
 321        aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 322
 323        if (!aconnector || !aconnector->mst_port)
 324                return false;
 325
 326        mst_port = aconnector->port;
 327
 328        mst_mgr = &aconnector->mst_port->mst_mgr;
 329
 330        if (!mst_mgr->mst_state)
 331                return false;
 332
 333        /* It's OK for this to fail */
 334        drm_dp_update_payload_part2(mst_mgr);
 335
 336        if (!enable)
 337                drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
 338
 339        return true;
 340}
 341
 342void dm_dtn_log_begin(struct dc_context *ctx,
 343        struct dc_log_buffer_ctx *log_ctx)
 344{
 345        static const char msg[] = "[dtn begin]\n";
 346
 347        if (!log_ctx) {
 348                pr_info("%s", msg);
 349                return;
 350        }
 351
 352        dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
 353}
 354
 355__printf(3, 4)
 356void dm_dtn_log_append_v(struct dc_context *ctx,
 357        struct dc_log_buffer_ctx *log_ctx,
 358        const char *msg, ...)
 359{
 360        va_list args;
 361        size_t total;
 362        int n;
 363
 364        if (!log_ctx) {
 365                /* No context, redirect to dmesg. */
 366                struct va_format vaf;
 367
 368                vaf.fmt = msg;
 369                vaf.va = &args;
 370
 371                va_start(args, msg);
 372                pr_info("%pV", &vaf);
 373                va_end(args);
 374
 375                return;
 376        }
 377
 378        /* Measure the output. */
 379        va_start(args, msg);
 380        n = vsnprintf(NULL, 0, msg, args);
 381        va_end(args);
 382
 383        if (n <= 0)
 384                return;
 385
 386        /* Reallocate the string buffer as needed. */
 387        total = log_ctx->pos + n + 1;
 388
 389        if (total > log_ctx->size) {
 390                char *buf = (char *)kvcalloc(total, sizeof(char), GFP_KERNEL);
 391
 392                if (buf) {
 393                        memcpy(buf, log_ctx->buf, log_ctx->pos);
 394                        kfree(log_ctx->buf);
 395
 396                        log_ctx->buf = buf;
 397                        log_ctx->size = total;
 398                }
 399        }
 400
 401        if (!log_ctx->buf)
 402                return;
 403
 404        /* Write the formatted string to the log buffer. */
 405        va_start(args, msg);
 406        n = vscnprintf(
 407                log_ctx->buf + log_ctx->pos,
 408                log_ctx->size - log_ctx->pos,
 409                msg,
 410                args);
 411        va_end(args);
 412
 413        if (n > 0)
 414                log_ctx->pos += n;
 415}
 416
 417void dm_dtn_log_end(struct dc_context *ctx,
 418        struct dc_log_buffer_ctx *log_ctx)
 419{
 420        static const char msg[] = "[dtn end]\n";
 421
 422        if (!log_ctx) {
 423                pr_info("%s", msg);
 424                return;
 425        }
 426
 427        dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
 428}
 429
 430bool dm_helpers_dp_mst_start_top_mgr(
 431                struct dc_context *ctx,
 432                const struct dc_link *link,
 433                bool boot)
 434{
 435        struct amdgpu_dm_connector *aconnector = link->priv;
 436
 437        if (!aconnector) {
 438                DRM_ERROR("Failed to find connector for link!");
 439                return false;
 440        }
 441
 442        if (boot) {
 443                DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
 444                                        aconnector, aconnector->base.base.id);
 445                return true;
 446        }
 447
 448        DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
 449                        aconnector, aconnector->base.base.id);
 450
 451        return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
 452}
 453
 454void dm_helpers_dp_mst_stop_top_mgr(
 455                struct dc_context *ctx,
 456                struct dc_link *link)
 457{
 458        struct amdgpu_dm_connector *aconnector = link->priv;
 459        uint8_t i;
 460
 461        if (!aconnector) {
 462                DRM_ERROR("Failed to find connector for link!");
 463                return;
 464        }
 465
 466        DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
 467                        aconnector, aconnector->base.base.id);
 468
 469        if (aconnector->mst_mgr.mst_state == true) {
 470                drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, false);
 471
 472                for (i = 0; i < MAX_SINKS_PER_LINK; i++) {
 473                        if (link->remote_sinks[i] == NULL)
 474                                continue;
 475
 476                        if (link->remote_sinks[i]->sink_signal ==
 477                            SIGNAL_TYPE_DISPLAY_PORT_MST) {
 478                                dc_link_remove_remote_sink(link, link->remote_sinks[i]);
 479
 480                                if (aconnector->dc_sink) {
 481                                        dc_sink_release(aconnector->dc_sink);
 482                                        aconnector->dc_sink = NULL;
 483                                        aconnector->dc_link->cur_link_settings.lane_count = 0;
 484                                }
 485                        }
 486                }
 487        }
 488}
 489
 490bool dm_helpers_dp_read_dpcd(
 491                struct dc_context *ctx,
 492                const struct dc_link *link,
 493                uint32_t address,
 494                uint8_t *data,
 495                uint32_t size)
 496{
 497
 498        struct amdgpu_dm_connector *aconnector = link->priv;
 499
 500        if (!aconnector) {
 501                DC_LOG_DC("Failed to find connector for link!\n");
 502                return false;
 503        }
 504
 505        return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address,
 506                        data, size) > 0;
 507}
 508
 509bool dm_helpers_dp_write_dpcd(
 510                struct dc_context *ctx,
 511                const struct dc_link *link,
 512                uint32_t address,
 513                const uint8_t *data,
 514                uint32_t size)
 515{
 516        struct amdgpu_dm_connector *aconnector = link->priv;
 517
 518        if (!aconnector) {
 519                DRM_ERROR("Failed to find connector for link!");
 520                return false;
 521        }
 522
 523        return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux,
 524                        address, (uint8_t *)data, size) > 0;
 525}
 526
 527bool dm_helpers_submit_i2c(
 528                struct dc_context *ctx,
 529                const struct dc_link *link,
 530                struct i2c_command *cmd)
 531{
 532        struct amdgpu_dm_connector *aconnector = link->priv;
 533        struct i2c_msg *msgs;
 534        int i = 0;
 535        int num = cmd->number_of_payloads;
 536        bool result;
 537
 538        if (!aconnector) {
 539                DRM_ERROR("Failed to find connector for link!");
 540                return false;
 541        }
 542
 543        msgs = kcalloc(num, sizeof(struct i2c_msg), GFP_KERNEL);
 544
 545        if (!msgs)
 546                return false;
 547
 548        for (i = 0; i < num; i++) {
 549                msgs[i].flags = cmd->payloads[i].write ? 0 : I2C_M_RD;
 550                msgs[i].addr = cmd->payloads[i].address;
 551                msgs[i].len = cmd->payloads[i].length;
 552                msgs[i].buf = cmd->payloads[i].data;
 553        }
 554
 555        result = i2c_transfer(&aconnector->i2c->base, msgs, num) == num;
 556
 557        kfree(msgs);
 558
 559        return result;
 560}
 561bool dm_helpers_dp_write_dsc_enable(
 562                struct dc_context *ctx,
 563                const struct dc_stream_state *stream,
 564                bool enable)
 565{
 566        uint8_t enable_dsc = enable ? 1 : 0;
 567        struct amdgpu_dm_connector *aconnector;
 568        uint8_t ret = 0;
 569
 570        if (!stream)
 571                return false;
 572
 573        if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
 574                aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 575
 576                if (!aconnector->dsc_aux)
 577                        return false;
 578
 579                ret = drm_dp_dpcd_write(aconnector->dsc_aux, DP_DSC_ENABLE, &enable_dsc, 1);
 580        }
 581
 582        if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
 583                ret = dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1);
 584                DC_LOG_DC("Send DSC %s to sst display\n", enable_dsc ? "enable" : "disable");
 585        }
 586
 587        return (ret > 0);
 588}
 589
 590bool dm_helpers_is_dp_sink_present(struct dc_link *link)
 591{
 592        bool dp_sink_present;
 593        struct amdgpu_dm_connector *aconnector = link->priv;
 594
 595        if (!aconnector) {
 596                BUG_ON("Failed to find connector for link!");
 597                return true;
 598        }
 599
 600        mutex_lock(&aconnector->dm_dp_aux.aux.hw_mutex);
 601        dp_sink_present = dc_link_is_dp_sink_present(link);
 602        mutex_unlock(&aconnector->dm_dp_aux.aux.hw_mutex);
 603        return dp_sink_present;
 604}
 605
 606enum dc_edid_status dm_helpers_read_local_edid(
 607                struct dc_context *ctx,
 608                struct dc_link *link,
 609                struct dc_sink *sink)
 610{
 611        struct amdgpu_dm_connector *aconnector = link->priv;
 612        struct drm_connector *connector = &aconnector->base;
 613        struct i2c_adapter *ddc;
 614        int retry = 3;
 615        enum dc_edid_status edid_status;
 616        struct edid *edid;
 617
 618        if (link->aux_mode)
 619                ddc = &aconnector->dm_dp_aux.aux.ddc;
 620        else
 621                ddc = &aconnector->i2c->base;
 622
 623        /* some dongles read edid incorrectly the first time,
 624         * do check sum and retry to make sure read correct edid.
 625         */
 626        do {
 627
 628                edid = drm_get_edid(&aconnector->base, ddc);
 629
 630                /* DP Compliance Test 4.2.2.6 */
 631                if (link->aux_mode && connector->edid_corrupt)
 632                        drm_dp_send_real_edid_checksum(&aconnector->dm_dp_aux.aux, connector->real_edid_checksum);
 633
 634                if (!edid && connector->edid_corrupt) {
 635                        connector->edid_corrupt = false;
 636                        return EDID_BAD_CHECKSUM;
 637                }
 638
 639                if (!edid)
 640                        return EDID_NO_RESPONSE;
 641
 642                sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
 643                memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
 644
 645                /* We don't need the original edid anymore */
 646                kfree(edid);
 647
 648                /* connector->display_info will be parsed from EDID and saved
 649                 * into drm_connector->display_info from edid by call stack
 650                 * below:
 651                 * drm_parse_ycbcr420_deep_color_info
 652                 * drm_parse_hdmi_forum_vsdb
 653                 * drm_parse_cea_ext
 654                 * drm_add_display_info
 655                 * drm_connector_update_edid_property
 656                 *
 657                 * drm_connector->display_info will be used by amdgpu_dm funcs,
 658                 * like fill_stream_properties_from_drm_display_mode
 659                 */
 660                amdgpu_dm_update_connector_after_detect(aconnector);
 661
 662                edid_status = dm_helpers_parse_edid_caps(
 663                                                ctx,
 664                                                &sink->dc_edid,
 665                                                &sink->edid_caps);
 666
 667        } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
 668
 669        if (edid_status != EDID_OK)
 670                DRM_ERROR("EDID err: %d, on connector: %s",
 671                                edid_status,
 672                                aconnector->base.name);
 673
 674        /* DP Compliance Test 4.2.2.3 */
 675        if (link->aux_mode)
 676                drm_dp_send_real_edid_checksum(&aconnector->dm_dp_aux.aux, sink->dc_edid.raw_edid[sink->dc_edid.length-1]);
 677
 678        return edid_status;
 679}
 680int dm_helper_dmub_aux_transfer_sync(
 681                struct dc_context *ctx,
 682                const struct dc_link *link,
 683                struct aux_payload *payload,
 684                enum aux_return_code_type *operation_result)
 685{
 686        return amdgpu_dm_process_dmub_aux_transfer_sync(ctx, link->link_index, payload, operation_result);
 687}
 688void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks)
 689{
 690        /* TODO: something */
 691}
 692
 693void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us)
 694{
 695        // TODO:
 696        //amdgpu_device_gpu_recover(dc_context->driver-context, NULL);
 697}
 698
 699void *dm_helpers_allocate_gpu_mem(
 700                struct dc_context *ctx,
 701                enum dc_gpu_mem_alloc_type type,
 702                size_t size,
 703                long long *addr)
 704{
 705        struct amdgpu_device *adev = ctx->driver_context;
 706        struct dal_allocation *da;
 707        u32 domain = (type == DC_MEM_ALLOC_TYPE_GART) ?
 708                AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM;
 709        int ret;
 710
 711        da = kzalloc(sizeof(struct dal_allocation), GFP_KERNEL);
 712        if (!da)
 713                return NULL;
 714
 715        ret = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
 716                                      domain, &da->bo,
 717                                      &da->gpu_addr, &da->cpu_ptr);
 718
 719        *addr = da->gpu_addr;
 720
 721        if (ret) {
 722                kfree(da);
 723                return NULL;
 724        }
 725
 726        /* add da to list in dm */
 727        list_add(&da->list, &adev->dm.da_list);
 728
 729        return da->cpu_ptr;
 730}
 731
 732void dm_helpers_free_gpu_mem(
 733                struct dc_context *ctx,
 734                enum dc_gpu_mem_alloc_type type,
 735                void *pvMem)
 736{
 737        struct amdgpu_device *adev = ctx->driver_context;
 738        struct dal_allocation *da;
 739
 740        /* walk the da list in DM */
 741        list_for_each_entry(da, &adev->dm.da_list, list) {
 742                if (pvMem == da->cpu_ptr) {
 743                        amdgpu_bo_free_kernel(&da->bo, &da->gpu_addr, &da->cpu_ptr);
 744                        list_del(&da->list);
 745                        kfree(da);
 746                        break;
 747                }
 748        }
 749}
 750
 751bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
 752{
 753        enum dc_irq_source irq_source;
 754        bool ret;
 755
 756        irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
 757
 758        ret = dc_interrupt_set(ctx->dc, irq_source, enable);
 759
 760        DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
 761                         enable ? "en" : "dis", ret);
 762        return ret;
 763}
 764
 765void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
 766{
 767        /* TODO: virtual DPCD */
 768        struct dc_link *link = stream->link;
 769        union down_spread_ctrl old_downspread;
 770        union down_spread_ctrl new_downspread;
 771
 772        if (link->aux_access_disabled)
 773                return;
 774
 775        if (!dm_helpers_dp_read_dpcd(link->ctx, link, DP_DOWNSPREAD_CTRL,
 776                                     &old_downspread.raw,
 777                                     sizeof(old_downspread)))
 778                return;
 779
 780        new_downspread.raw = old_downspread.raw;
 781        new_downspread.bits.IGNORE_MSA_TIMING_PARAM =
 782                (stream->ignore_msa_timing_param) ? 1 : 0;
 783
 784        if (new_downspread.raw != old_downspread.raw)
 785                dm_helpers_dp_write_dpcd(link->ctx, link, DP_DOWNSPREAD_CTRL,
 786                                         &new_downspread.raw,
 787                                         sizeof(new_downspread));
 788}
 789