linux/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012-15 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/slab.h>
  27
  28#include "dm_services.h"
  29#include "dm_helpers.h"
  30#include "gpio_service_interface.h"
  31#include "include/ddc_service_types.h"
  32#include "include/grph_object_id.h"
  33#include "include/dpcd_defs.h"
  34#include "include/logger_interface.h"
  35#include "include/vector.h"
  36#include "core_types.h"
  37#include "dc_link_ddc.h"
  38#include "dce/dce_aux.h"
  39#include "dmub/inc/dmub_cmd.h"
  40
  41#define DC_LOGGER_INIT(logger)
  42
  43static const uint8_t DP_VGA_DONGLE_BRANCH_DEV_NAME[] = "DpVga";
  44/* DP to Dual link DVI converter */
  45static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa";
  46static const uint8_t DP_DVI_CONVERTER_ID_5[] = "3393N2";
  47
  48#define AUX_POWER_UP_WA_DELAY 500
  49#define I2C_OVER_AUX_DEFER_WA_DELAY 70
  50#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40
  51#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1
  52
  53/* CV smart dongle slave address for retrieving supported HDTV modes*/
  54#define CV_SMART_DONGLE_ADDRESS 0x20
  55/* DVI-HDMI dongle slave address for retrieving dongle signature*/
  56#define DVI_HDMI_DONGLE_ADDRESS 0x68
  57struct dvi_hdmi_dongle_signature_data {
  58        int8_t vendor[3];/* "AMD" */
  59        uint8_t version[2];
  60        uint8_t size;
  61        int8_t id[11];/* "6140063500G"*/
  62};
  63/* DP-HDMI dongle slave address for retrieving dongle signature*/
  64#define DP_HDMI_DONGLE_ADDRESS 0x40
  65static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR";
  66#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04
  67
  68struct dp_hdmi_dongle_signature_data {
  69        int8_t id[15];/* "DP-HDMI ADAPTOR"*/
  70        uint8_t eot;/* end of transmition '\x4' */
  71};
  72
  73/* SCDC Address defines (HDMI 2.0)*/
  74#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3
  75#define HDMI_SCDC_ADDRESS  0x54
  76#define HDMI_SCDC_SINK_VERSION 0x01
  77#define HDMI_SCDC_SOURCE_VERSION 0x02
  78#define HDMI_SCDC_UPDATE_0 0x10
  79#define HDMI_SCDC_TMDS_CONFIG 0x20
  80#define HDMI_SCDC_SCRAMBLER_STATUS 0x21
  81#define HDMI_SCDC_CONFIG_0 0x30
  82#define HDMI_SCDC_STATUS_FLAGS 0x40
  83#define HDMI_SCDC_ERR_DETECT 0x50
  84#define HDMI_SCDC_TEST_CONFIG 0xC0
  85
  86union hdmi_scdc_update_read_data {
  87        uint8_t byte[2];
  88        struct {
  89                uint8_t STATUS_UPDATE:1;
  90                uint8_t CED_UPDATE:1;
  91                uint8_t RR_TEST:1;
  92                uint8_t RESERVED:5;
  93                uint8_t RESERVED2:8;
  94        } fields;
  95};
  96
  97union hdmi_scdc_status_flags_data {
  98        uint8_t byte[2];
  99        struct {
 100                uint8_t CLOCK_DETECTED:1;
 101                uint8_t CH0_LOCKED:1;
 102                uint8_t CH1_LOCKED:1;
 103                uint8_t CH2_LOCKED:1;
 104                uint8_t RESERVED:4;
 105                uint8_t RESERVED2:8;
 106                uint8_t RESERVED3:8;
 107
 108        } fields;
 109};
 110
 111union hdmi_scdc_ced_data {
 112        uint8_t byte[7];
 113        struct {
 114                uint8_t CH0_8LOW:8;
 115                uint8_t CH0_7HIGH:7;
 116                uint8_t CH0_VALID:1;
 117                uint8_t CH1_8LOW:8;
 118                uint8_t CH1_7HIGH:7;
 119                uint8_t CH1_VALID:1;
 120                uint8_t CH2_8LOW:8;
 121                uint8_t CH2_7HIGH:7;
 122                uint8_t CH2_VALID:1;
 123                uint8_t CHECKSUM:8;
 124                uint8_t RESERVED:8;
 125                uint8_t RESERVED2:8;
 126                uint8_t RESERVED3:8;
 127                uint8_t RESERVED4:4;
 128        } fields;
 129};
 130
 131struct i2c_payloads {
 132        struct vector payloads;
 133};
 134
 135struct aux_payloads {
 136        struct vector payloads;
 137};
 138
 139static bool dal_ddc_i2c_payloads_create(
 140                struct dc_context *ctx,
 141                struct i2c_payloads *payloads,
 142                uint32_t count)
 143{
 144        if (dal_vector_construct(
 145                &payloads->payloads, ctx, count, sizeof(struct i2c_payload)))
 146                return true;
 147
 148        return false;
 149}
 150
 151static struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p)
 152{
 153        return (struct i2c_payload *)p->payloads.container;
 154}
 155
 156static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p)
 157{
 158        return p->payloads.count;
 159}
 160
 161#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 162
 163void dal_ddc_i2c_payloads_add(
 164        struct i2c_payloads *payloads,
 165        uint32_t address,
 166        uint32_t len,
 167        uint8_t *data,
 168        bool write)
 169{
 170        uint32_t payload_size = EDID_SEGMENT_SIZE;
 171        uint32_t pos;
 172
 173        for (pos = 0; pos < len; pos += payload_size) {
 174                struct i2c_payload payload = {
 175                        .write = write,
 176                        .address = address,
 177                        .length = DDC_MIN(payload_size, len - pos),
 178                        .data = data + pos };
 179                dal_vector_append(&payloads->payloads, &payload);
 180        }
 181
 182}
 183
 184static void ddc_service_construct(
 185        struct ddc_service *ddc_service,
 186        struct ddc_service_init_data *init_data)
 187{
 188        enum connector_id connector_id =
 189                dal_graphics_object_id_get_connector_id(init_data->id);
 190
 191        struct gpio_service *gpio_service = init_data->ctx->gpio_service;
 192        struct graphics_object_i2c_info i2c_info;
 193        struct gpio_ddc_hw_info hw_info;
 194        struct dc_bios *dcb = init_data->ctx->dc_bios;
 195
 196        ddc_service->link = init_data->link;
 197        ddc_service->ctx = init_data->ctx;
 198
 199        if (init_data->is_dpia_link ||
 200            dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info) != BP_RESULT_OK) {
 201                ddc_service->ddc_pin = NULL;
 202        } else {
 203                DC_LOGGER_INIT(ddc_service->ctx->logger);
 204                DC_LOG_DC("BIOS object table - i2c_line: %d", i2c_info.i2c_line);
 205                DC_LOG_DC("BIOS object table - i2c_engine_id: %d", i2c_info.i2c_engine_id);
 206
 207                hw_info.ddc_channel = i2c_info.i2c_line;
 208                if (ddc_service->link != NULL)
 209                        hw_info.hw_supported = i2c_info.i2c_hw_assist;
 210                else
 211                        hw_info.hw_supported = false;
 212
 213                ddc_service->ddc_pin = dal_gpio_create_ddc(
 214                        gpio_service,
 215                        i2c_info.gpio_info.clk_a_register_index,
 216                        1 << i2c_info.gpio_info.clk_a_shift,
 217                        &hw_info);
 218        }
 219
 220        ddc_service->flags.EDID_QUERY_DONE_ONCE = false;
 221        ddc_service->flags.FORCE_READ_REPEATED_START = false;
 222        ddc_service->flags.EDID_STRESS_READ = false;
 223
 224        ddc_service->flags.IS_INTERNAL_DISPLAY =
 225                connector_id == CONNECTOR_ID_EDP ||
 226                connector_id == CONNECTOR_ID_LVDS;
 227
 228        ddc_service->wa.raw = 0;
 229}
 230
 231struct ddc_service *dal_ddc_service_create(
 232        struct ddc_service_init_data *init_data)
 233{
 234        struct ddc_service *ddc_service;
 235
 236        ddc_service = kzalloc(sizeof(struct ddc_service), GFP_KERNEL);
 237
 238        if (!ddc_service)
 239                return NULL;
 240
 241        ddc_service_construct(ddc_service, init_data);
 242        return ddc_service;
 243}
 244
 245static void ddc_service_destruct(struct ddc_service *ddc)
 246{
 247        if (ddc->ddc_pin)
 248                dal_gpio_destroy_ddc(&ddc->ddc_pin);
 249}
 250
 251void dal_ddc_service_destroy(struct ddc_service **ddc)
 252{
 253        if (!ddc || !*ddc) {
 254                BREAK_TO_DEBUGGER();
 255                return;
 256        }
 257        ddc_service_destruct(*ddc);
 258        kfree(*ddc);
 259        *ddc = NULL;
 260}
 261
 262enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc)
 263{
 264        return DDC_SERVICE_TYPE_CONNECTOR;
 265}
 266
 267void dal_ddc_service_set_transaction_type(
 268        struct ddc_service *ddc,
 269        enum ddc_transaction_type type)
 270{
 271        ddc->transaction_type = type;
 272}
 273
 274bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc)
 275{
 276        switch (ddc->transaction_type) {
 277        case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
 278        case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
 279        case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER:
 280                return true;
 281        default:
 282                break;
 283        }
 284        return false;
 285}
 286
 287void ddc_service_set_dongle_type(struct ddc_service *ddc,
 288                enum display_dongle_type dongle_type)
 289{
 290        ddc->dongle_type = dongle_type;
 291}
 292
 293static uint32_t defer_delay_converter_wa(
 294        struct ddc_service *ddc,
 295        uint32_t defer_delay)
 296{
 297        struct dc_link *link = ddc->link;
 298
 299        if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER &&
 300                link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
 301                (link->dpcd_caps.branch_fw_revision[0] < 0x01 ||
 302                                (link->dpcd_caps.branch_fw_revision[0] == 0x01 &&
 303                                link->dpcd_caps.branch_fw_revision[1] < 0x40)) &&
 304                !memcmp(link->dpcd_caps.branch_dev_name,
 305                    DP_VGA_DONGLE_BRANCH_DEV_NAME,
 306                        sizeof(link->dpcd_caps.branch_dev_name)))
 307
 308                return defer_delay > DPVGA_DONGLE_AUX_DEFER_WA_DELAY ?
 309                        defer_delay : DPVGA_DONGLE_AUX_DEFER_WA_DELAY;
 310
 311        if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
 312            !memcmp(link->dpcd_caps.branch_dev_name,
 313                    DP_DVI_CONVERTER_ID_4,
 314                    sizeof(link->dpcd_caps.branch_dev_name)))
 315                return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ?
 316                        defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY;
 317        if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_006037 &&
 318            !memcmp(link->dpcd_caps.branch_dev_name,
 319                    DP_DVI_CONVERTER_ID_5,
 320                    sizeof(link->dpcd_caps.branch_dev_name)))
 321                return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY_1MS ?
 322                        I2C_OVER_AUX_DEFER_WA_DELAY_1MS : defer_delay;
 323
 324        return defer_delay;
 325}
 326
 327#define DP_TRANSLATOR_DELAY 5
 328
 329uint32_t get_defer_delay(struct ddc_service *ddc)
 330{
 331        uint32_t defer_delay = 0;
 332
 333        switch (ddc->transaction_type) {
 334        case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
 335                if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) ||
 336                        (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) ||
 337                        (DISPLAY_DONGLE_DP_HDMI_CONVERTER ==
 338                                ddc->dongle_type)) {
 339
 340                        defer_delay = DP_TRANSLATOR_DELAY;
 341
 342                        defer_delay =
 343                                defer_delay_converter_wa(ddc, defer_delay);
 344
 345                } else /*sink has a delay different from an Active Converter*/
 346                        defer_delay = 0;
 347                break;
 348        case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
 349                defer_delay = DP_TRANSLATOR_DELAY;
 350                break;
 351        default:
 352                break;
 353        }
 354        return defer_delay;
 355}
 356
 357static bool i2c_read(
 358        struct ddc_service *ddc,
 359        uint32_t address,
 360        uint8_t *buffer,
 361        uint32_t len)
 362{
 363        uint8_t offs_data = 0;
 364        struct i2c_payload payloads[2] = {
 365                {
 366                .write = true,
 367                .address = address,
 368                .length = 1,
 369                .data = &offs_data },
 370                {
 371                .write = false,
 372                .address = address,
 373                .length = len,
 374                .data = buffer } };
 375
 376        struct i2c_command command = {
 377                .payloads = payloads,
 378                .number_of_payloads = 2,
 379                .engine = DDC_I2C_COMMAND_ENGINE,
 380                .speed = ddc->ctx->dc->caps.i2c_speed_in_khz };
 381
 382        return dm_helpers_submit_i2c(
 383                        ddc->ctx,
 384                        ddc->link,
 385                        &command);
 386}
 387
 388void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
 389        struct ddc_service *ddc,
 390        struct display_sink_capability *sink_cap)
 391{
 392        uint8_t i;
 393        bool is_valid_hdmi_signature;
 394        enum display_dongle_type *dongle = &sink_cap->dongle_type;
 395        uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE];
 396        bool is_type2_dongle = false;
 397        int retry_count = 2;
 398        struct dp_hdmi_dongle_signature_data *dongle_signature;
 399
 400        /* Assume we have no valid DP passive dongle connected */
 401        *dongle = DISPLAY_DONGLE_NONE;
 402        sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
 403
 404        /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/
 405        if (!i2c_read(
 406                ddc,
 407                DP_HDMI_DONGLE_ADDRESS,
 408                type2_dongle_buf,
 409                sizeof(type2_dongle_buf))) {
 410                /* Passive HDMI dongles can sometimes fail here without retrying*/
 411                while (retry_count > 0) {
 412                        if (i2c_read(ddc,
 413                                DP_HDMI_DONGLE_ADDRESS,
 414                                type2_dongle_buf,
 415                                sizeof(type2_dongle_buf)))
 416                                break;
 417                        retry_count--;
 418                }
 419                if (retry_count == 0) {
 420                        *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
 421                        sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
 422
 423                        CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf),
 424                                        "DP-DVI passive dongle %dMhz: ",
 425                                        DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
 426                        return;
 427                }
 428        }
 429
 430        /* Check if Type 2 dongle.*/
 431        if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID)
 432                is_type2_dongle = true;
 433
 434        dongle_signature =
 435                (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf;
 436
 437        is_valid_hdmi_signature = true;
 438
 439        /* Check EOT */
 440        if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) {
 441                is_valid_hdmi_signature = false;
 442        }
 443
 444        /* Check signature */
 445        for (i = 0; i < sizeof(dongle_signature->id); ++i) {
 446                /* If its not the right signature,
 447                 * skip mismatch in subversion byte.*/
 448                if (dongle_signature->id[i] !=
 449                        dp_hdmi_dongle_signature_str[i] && i != 3) {
 450
 451                        if (is_type2_dongle) {
 452                                is_valid_hdmi_signature = false;
 453                                break;
 454                        }
 455
 456                }
 457        }
 458
 459        if (is_type2_dongle) {
 460                uint32_t max_tmds_clk =
 461                        type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK];
 462
 463                max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2;
 464
 465                if (0 == max_tmds_clk ||
 466                                max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK ||
 467                                max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) {
 468                        *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
 469
 470                        CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
 471                                        sizeof(type2_dongle_buf),
 472                                        "DP-DVI passive dongle %dMhz: ",
 473                                        DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
 474                } else {
 475                        if (is_valid_hdmi_signature == true) {
 476                                *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
 477
 478                                CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
 479                                                sizeof(type2_dongle_buf),
 480                                                "Type 2 DP-HDMI passive dongle %dMhz: ",
 481                                                max_tmds_clk);
 482                        } else {
 483                                *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
 484
 485                                CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
 486                                                sizeof(type2_dongle_buf),
 487                                                "Type 2 DP-HDMI passive dongle (no signature) %dMhz: ",
 488                                                max_tmds_clk);
 489
 490                        }
 491
 492                        /* Multiply by 1000 to convert to kHz. */
 493                        sink_cap->max_hdmi_pixel_clock =
 494                                max_tmds_clk * 1000;
 495                }
 496                sink_cap->is_dongle_type_one = false;
 497
 498        } else {
 499                if (is_valid_hdmi_signature == true) {
 500                        *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
 501
 502                        CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
 503                                        sizeof(type2_dongle_buf),
 504                                        "Type 1 DP-HDMI passive dongle %dMhz: ",
 505                                        sink_cap->max_hdmi_pixel_clock / 1000);
 506                } else {
 507                        *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
 508
 509                        CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
 510                                        sizeof(type2_dongle_buf),
 511                                        "Type 1 DP-HDMI passive dongle (no signature) %dMhz: ",
 512                                        sink_cap->max_hdmi_pixel_clock / 1000);
 513                }
 514                sink_cap->is_dongle_type_one = true;
 515        }
 516
 517        return;
 518}
 519
 520enum {
 521        DP_SINK_CAP_SIZE =
 522                DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1
 523};
 524
 525bool dal_ddc_service_query_ddc_data(
 526        struct ddc_service *ddc,
 527        uint32_t address,
 528        uint8_t *write_buf,
 529        uint32_t write_size,
 530        uint8_t *read_buf,
 531        uint32_t read_size)
 532{
 533        bool success = true;
 534        uint32_t payload_size =
 535                dal_ddc_service_is_in_aux_transaction_mode(ddc) ?
 536                        DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
 537
 538        uint32_t write_payloads =
 539                (write_size + payload_size - 1) / payload_size;
 540
 541        uint32_t read_payloads =
 542                (read_size + payload_size - 1) / payload_size;
 543
 544        uint32_t payloads_num = write_payloads + read_payloads;
 545
 546        if (!payloads_num)
 547                return false;
 548
 549        if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
 550                struct aux_payload payload;
 551
 552                payload.i2c_over_aux = true;
 553                payload.address = address;
 554                payload.reply = NULL;
 555                payload.defer_delay = get_defer_delay(ddc);
 556                payload.write_status_update = false;
 557
 558                if (write_size != 0) {
 559                        payload.write = true;
 560                        /* should not set mot (middle of transaction) to 0
 561                         * if there are pending read payloads
 562                         */
 563                        payload.mot = !(read_size == 0);
 564                        payload.length = write_size;
 565                        payload.data = write_buf;
 566
 567                        success = dal_ddc_submit_aux_command(ddc, &payload);
 568                }
 569
 570                if (read_size != 0 && success) {
 571                        payload.write = false;
 572                        /* should set mot (middle of transaction) to 0
 573                         * since it is the last payload to send
 574                         */
 575                        payload.mot = false;
 576                        payload.length = read_size;
 577                        payload.data = read_buf;
 578
 579                        success = dal_ddc_submit_aux_command(ddc, &payload);
 580                }
 581        } else {
 582                struct i2c_command command = {0};
 583                struct i2c_payloads payloads;
 584
 585                if (!dal_ddc_i2c_payloads_create(ddc->ctx, &payloads, payloads_num))
 586                        return false;
 587
 588                command.payloads = dal_ddc_i2c_payloads_get(&payloads);
 589                command.number_of_payloads = 0;
 590                command.engine = DDC_I2C_COMMAND_ENGINE;
 591                command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
 592
 593                dal_ddc_i2c_payloads_add(
 594                        &payloads, address, write_size, write_buf, true);
 595
 596                dal_ddc_i2c_payloads_add(
 597                        &payloads, address, read_size, read_buf, false);
 598
 599                command.number_of_payloads =
 600                        dal_ddc_i2c_payloads_get_count(&payloads);
 601
 602                success = dm_helpers_submit_i2c(
 603                                ddc->ctx,
 604                                ddc->link,
 605                                &command);
 606
 607                dal_vector_destruct(&payloads.payloads);
 608        }
 609
 610        return success;
 611}
 612
 613bool dal_ddc_submit_aux_command(struct ddc_service *ddc,
 614                struct aux_payload *payload)
 615{
 616        uint32_t retrieved = 0;
 617        bool ret = false;
 618
 619        if (!ddc)
 620                return false;
 621
 622        if (!payload)
 623                return false;
 624
 625        do {
 626                struct aux_payload current_payload;
 627                bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >=
 628                                payload->length;
 629                uint32_t payload_length = is_end_of_payload ?
 630                                payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE;
 631
 632                current_payload.address = payload->address;
 633                current_payload.data = &payload->data[retrieved];
 634                current_payload.defer_delay = payload->defer_delay;
 635                current_payload.i2c_over_aux = payload->i2c_over_aux;
 636                current_payload.length = payload_length;
 637                /* set mot (middle of transaction) to false if it is the last payload */
 638                current_payload.mot = is_end_of_payload ? payload->mot:true;
 639                current_payload.write_status_update = false;
 640                current_payload.reply = payload->reply;
 641                current_payload.write = payload->write;
 642
 643                ret = dc_link_aux_transfer_with_retries(ddc, &current_payload);
 644
 645                retrieved += payload_length;
 646        } while (retrieved < payload->length && ret == true);
 647
 648        return ret;
 649}
 650
 651/* dc_link_aux_transfer_raw() - Attempt to transfer
 652 * the given aux payload.  This function does not perform
 653 * retries or handle error states.  The reply is returned
 654 * in the payload->reply and the result through
 655 * *operation_result.  Returns the number of bytes transferred,
 656 * or -1 on a failure.
 657 */
 658int dc_link_aux_transfer_raw(struct ddc_service *ddc,
 659                struct aux_payload *payload,
 660                enum aux_return_code_type *operation_result)
 661{
 662        if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc ||
 663            !ddc->ddc_pin) {
 664                return dce_aux_transfer_dmub_raw(ddc, payload, operation_result);
 665        } else {
 666                return dce_aux_transfer_raw(ddc, payload, operation_result);
 667        }
 668}
 669
 670/* dc_link_aux_transfer_with_retries() - Attempt to submit an
 671 * aux payload, retrying on timeouts, defers, and busy states
 672 * as outlined in the DP spec.  Returns true if the request
 673 * was successful.
 674 *
 675 * Unless you want to implement your own retry semantics, this
 676 * is probably the one you want.
 677 */
 678bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc,
 679                struct aux_payload *payload)
 680{
 681        return dce_aux_transfer_with_retries(ddc, payload);
 682}
 683
 684
 685bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc,
 686                uint32_t timeout)
 687{
 688        bool result = false;
 689        struct ddc *ddc_pin = ddc->ddc_pin;
 690
 691        /* Do not try to access nonexistent DDC pin. */
 692        if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY)
 693                return true;
 694
 695        if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) {
 696                ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout);
 697                result = true;
 698        }
 699        return result;
 700}
 701
 702/*test only function*/
 703void dal_ddc_service_set_ddc_pin(
 704        struct ddc_service *ddc_service,
 705        struct ddc *ddc)
 706{
 707        ddc_service->ddc_pin = ddc;
 708}
 709
 710struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service)
 711{
 712        return ddc_service->ddc_pin;
 713}
 714
 715void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service,
 716                uint32_t pix_clk,
 717                bool lte_340_scramble)
 718{
 719        bool over_340_mhz = pix_clk > 340000 ? 1 : 0;
 720        uint8_t slave_address = HDMI_SCDC_ADDRESS;
 721        uint8_t offset = HDMI_SCDC_SINK_VERSION;
 722        uint8_t sink_version = 0;
 723        uint8_t write_buffer[2] = {0};
 724        /*Lower than 340 Scramble bit from SCDC caps*/
 725
 726        if (ddc_service->link->local_sink &&
 727                ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
 728                return;
 729
 730        dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
 731                        sizeof(offset), &sink_version, sizeof(sink_version));
 732        if (sink_version == 1) {
 733                /*Source Version = 1*/
 734                write_buffer[0] = HDMI_SCDC_SOURCE_VERSION;
 735                write_buffer[1] = 1;
 736                dal_ddc_service_query_ddc_data(ddc_service, slave_address,
 737                                write_buffer, sizeof(write_buffer), NULL, 0);
 738                /*Read Request from SCDC caps*/
 739        }
 740        write_buffer[0] = HDMI_SCDC_TMDS_CONFIG;
 741
 742        if (over_340_mhz) {
 743                write_buffer[1] = 3;
 744        } else if (lte_340_scramble) {
 745                write_buffer[1] = 1;
 746        } else {
 747                write_buffer[1] = 0;
 748        }
 749        dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer,
 750                        sizeof(write_buffer), NULL, 0);
 751}
 752
 753void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service)
 754{
 755        uint8_t slave_address = HDMI_SCDC_ADDRESS;
 756        uint8_t offset = HDMI_SCDC_TMDS_CONFIG;
 757        uint8_t tmds_config = 0;
 758
 759        if (ddc_service->link->local_sink &&
 760                ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
 761                return;
 762
 763        dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
 764                        sizeof(offset), &tmds_config, sizeof(tmds_config));
 765        if (tmds_config & 0x1) {
 766                union hdmi_scdc_status_flags_data status_data = {0};
 767                uint8_t scramble_status = 0;
 768
 769                offset = HDMI_SCDC_SCRAMBLER_STATUS;
 770                dal_ddc_service_query_ddc_data(ddc_service, slave_address,
 771                                &offset, sizeof(offset), &scramble_status,
 772                                sizeof(scramble_status));
 773                offset = HDMI_SCDC_STATUS_FLAGS;
 774                dal_ddc_service_query_ddc_data(ddc_service, slave_address,
 775                                &offset, sizeof(offset), status_data.byte,
 776                                sizeof(status_data.byte));
 777        }
 778}
 779
 780