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