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