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