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 /* FILE POLICY AND INTENDED USAGE: 27 * 28 * This file implements generic display communication protocols such as i2c, aux 29 * and scdc. The file should not contain any specific applications of these 30 * protocols such as display capability query, detection, or handshaking such as 31 * link training. 32 */ 33 #include "link_ddc.h" 34 #include "link_hdmi_frl.h" 35 #include "vector.h" 36 #include "dce/dce_aux.h" 37 #include "dal_asic_id.h" 38 #include "link_dpcd.h" 39 #include "dm_helpers.h" 40 #include "atomfirmware.h" 41 42 #define DC_LOGGER \ 43 ddc_service->ctx->logger 44 #define DC_LOGGER_INIT(logger) 45 46 static const uint8_t DP_VGA_DONGLE_BRANCH_DEV_NAME[] = "DpVga"; 47 /* DP to Dual link DVI converter */ 48 static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa"; 49 static const uint8_t DP_DVI_CONVERTER_ID_5[] = "3393N2"; 50 51 struct i2c_payloads { 52 struct vector payloads; 53 }; 54 55 static bool i2c_payloads_create( 56 struct dc_context *ctx, 57 struct i2c_payloads *payloads, 58 uint32_t count) 59 { 60 if (dal_vector_construct( 61 &payloads->payloads, ctx, count, sizeof(struct i2c_payload))) 62 return true; 63 64 return false; 65 } 66 67 static struct i2c_payload *i2c_payloads_get(struct i2c_payloads *p) 68 { 69 return (struct i2c_payload *)p->payloads.container; 70 } 71 72 static uint32_t i2c_payloads_get_count(struct i2c_payloads *p) 73 { 74 return p->payloads.count; 75 } 76 77 static void i2c_payloads_destroy(struct i2c_payloads *p) 78 { 79 if (!p) 80 return; 81 82 dal_vector_destruct(&p->payloads); 83 } 84 85 #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) 86 87 static void i2c_payloads_add( 88 struct i2c_payloads *payloads, 89 uint32_t address, 90 uint32_t len, 91 uint8_t *data, 92 bool write) 93 { 94 uint32_t payload_size = EDID_SEGMENT_SIZE; 95 uint32_t pos; 96 97 for (pos = 0; pos < len; pos += payload_size) { 98 struct i2c_payload payload = { 99 .write = write, 100 .address = (uint8_t)address, 101 .length = DDC_MIN(payload_size, len - pos), 102 .data = data + pos }; 103 dal_vector_append(&payloads->payloads, &payload); 104 } 105 106 } 107 108 static void ddc_service_construct( 109 struct ddc_service *ddc_service, 110 struct ddc_service_init_data *init_data) 111 { 112 enum connector_id connector_id = 113 dal_graphics_object_id_get_connector_id(init_data->id); 114 115 struct gpio_service *gpio_service = init_data->ctx->gpio_service; 116 struct graphics_object_i2c_info i2c_info; 117 struct gpio_ddc_hw_info hw_info; 118 struct dc_bios *dcb = init_data->ctx->dc_bios; 119 120 ddc_service->link = init_data->link; 121 ddc_service->ctx = init_data->ctx; 122 123 if (ddc_service->link && ddc_service->ctx->dc->config.dp_connector_no_native_i2c && 124 ddc_service->link->no_ddc_pin) { 125 // Obtain aux instance info from i2c_info without GPIO DDC pin info 126 if (dcb->funcs->get_connector_aux_info(dcb, init_data->id, &i2c_info) == BP_RESULT_OK) 127 ddc_service->link->aux_hw_inst = (uint8_t)i2c_info.i2c_line; 128 } else { 129 if (init_data->is_dpia_link || 130 dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info) != BP_RESULT_OK) { 131 ddc_service->ddc_pin = NULL; 132 } else { 133 DC_LOGGER_INIT(ddc_service->ctx->logger); 134 DC_LOG_DC("BIOS object table - i2c_line: %d", i2c_info.i2c_line); 135 DC_LOG_DC("BIOS object table - i2c_engine_id: %d", i2c_info.i2c_engine_id); 136 137 hw_info.ddc_channel = i2c_info.i2c_line; 138 if (ddc_service->link != NULL) 139 hw_info.hw_supported = i2c_info.i2c_hw_assist; 140 else 141 hw_info.hw_supported = false; 142 143 ddc_service->ddc_pin = dal_gpio_create_ddc( 144 gpio_service, 145 i2c_info.gpio_info.clk_a_register_index, 146 1 << i2c_info.gpio_info.clk_a_shift, 147 &hw_info); 148 } 149 } 150 151 ddc_service->flags.EDID_QUERY_DONE_ONCE = false; 152 ddc_service->flags.FORCE_READ_REPEATED_START = false; 153 ddc_service->flags.EDID_STRESS_READ = false; 154 155 ddc_service->flags.IS_INTERNAL_DISPLAY = 156 connector_id == CONNECTOR_ID_EDP || 157 connector_id == CONNECTOR_ID_LVDS; 158 159 ddc_service->wa.raw = 0; 160 } 161 162 struct ddc_service *link_create_ddc_service( 163 struct ddc_service_init_data *init_data) 164 { 165 struct ddc_service *ddc_service; 166 167 ddc_service = kzalloc_obj(struct ddc_service); 168 169 if (!ddc_service) 170 return NULL; 171 172 ddc_service_construct(ddc_service, init_data); 173 return ddc_service; 174 } 175 176 static void ddc_service_destruct(struct ddc_service *ddc) 177 { 178 if (ddc->ddc_pin) 179 dal_gpio_destroy_ddc(&ddc->ddc_pin); 180 } 181 182 void link_destroy_ddc_service(struct ddc_service **ddc) 183 { 184 if (!ddc || !*ddc) { 185 BREAK_TO_DEBUGGER(); 186 return; 187 } 188 ddc_service_destruct(*ddc); 189 kfree(*ddc); 190 *ddc = NULL; 191 } 192 193 void set_ddc_transaction_type( 194 struct ddc_service *ddc, 195 enum ddc_transaction_type type) 196 { 197 ddc->transaction_type = type; 198 } 199 200 bool link_is_in_aux_transaction_mode(struct ddc_service *ddc) 201 { 202 switch (ddc->transaction_type) { 203 case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: 204 case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: 205 case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER: 206 return true; 207 default: 208 break; 209 } 210 return false; 211 } 212 213 void set_dongle_type(struct ddc_service *ddc, 214 enum display_dongle_type dongle_type) 215 { 216 ddc->dongle_type = dongle_type; 217 } 218 219 static uint32_t defer_delay_converter_wa( 220 struct ddc_service *ddc, 221 uint32_t defer_delay) 222 { 223 struct dc_link *link = ddc->link; 224 225 if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER && 226 link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 && 227 (link->dpcd_caps.branch_fw_revision[0] < 0x01 || 228 (link->dpcd_caps.branch_fw_revision[0] == 0x01 && 229 link->dpcd_caps.branch_fw_revision[1] < 0x40)) && 230 !memcmp(link->dpcd_caps.branch_dev_name, 231 DP_VGA_DONGLE_BRANCH_DEV_NAME, 232 sizeof(link->dpcd_caps.branch_dev_name))) 233 234 return defer_delay > DPVGA_DONGLE_AUX_DEFER_WA_DELAY ? 235 defer_delay : DPVGA_DONGLE_AUX_DEFER_WA_DELAY; 236 237 if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 && 238 !memcmp(link->dpcd_caps.branch_dev_name, 239 DP_DVI_CONVERTER_ID_4, 240 sizeof(link->dpcd_caps.branch_dev_name))) 241 return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ? 242 defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY; 243 if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_006037 && 244 !memcmp(link->dpcd_caps.branch_dev_name, 245 DP_DVI_CONVERTER_ID_5, 246 sizeof(link->dpcd_caps.branch_dev_name))) 247 return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY_1MS ? 248 I2C_OVER_AUX_DEFER_WA_DELAY_1MS : defer_delay; 249 250 return defer_delay; 251 } 252 253 #define DP_TRANSLATOR_DELAY 5 254 255 uint32_t link_get_aux_defer_delay(struct ddc_service *ddc) 256 { 257 uint32_t defer_delay = 0; 258 259 switch (ddc->transaction_type) { 260 case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: 261 if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) || 262 (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) || 263 (DISPLAY_DONGLE_DP_HDMI_CONVERTER == 264 ddc->dongle_type)) { 265 266 defer_delay = DP_TRANSLATOR_DELAY; 267 268 defer_delay = 269 defer_delay_converter_wa(ddc, defer_delay); 270 271 } else /*sink has a delay different from an Active Converter*/ 272 defer_delay = 0; 273 break; 274 case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: 275 defer_delay = DP_TRANSLATOR_DELAY; 276 break; 277 default: 278 break; 279 } 280 return defer_delay; 281 } 282 283 static bool submit_aux_command(struct ddc_service *ddc, 284 struct aux_payload *payload) 285 { 286 uint32_t retrieved = 0; 287 bool ret = false; 288 289 if (!ddc) 290 return false; 291 292 if (!payload) 293 return false; 294 295 do { 296 struct aux_payload current_payload; 297 bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >= 298 payload->length; 299 uint32_t payload_length = is_end_of_payload ? 300 payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE; 301 302 current_payload.address = payload->address; 303 current_payload.data = &payload->data[retrieved]; 304 current_payload.defer_delay = payload->defer_delay; 305 current_payload.i2c_over_aux = payload->i2c_over_aux; 306 current_payload.length = payload_length; 307 /* set mot (middle of transaction) to false if it is the last payload */ 308 current_payload.mot = is_end_of_payload ? payload->mot:true; 309 current_payload.write_status_update = false; 310 current_payload.reply = payload->reply; 311 current_payload.write = payload->write; 312 313 ret = link_aux_transfer_with_retries_no_mutex(ddc, ¤t_payload); 314 315 retrieved += payload_length; 316 } while (retrieved < payload->length && ret == true); 317 318 return ret; 319 } 320 321 bool link_query_ddc_data( 322 struct ddc_service *ddc, 323 uint32_t address, 324 uint8_t *write_buf, 325 uint32_t write_size, 326 uint8_t *read_buf, 327 uint32_t read_size) 328 { 329 bool success = true; 330 uint32_t payload_size = 331 link_is_in_aux_transaction_mode(ddc) ? 332 DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE; 333 334 uint32_t write_payloads = 335 (write_size + payload_size - 1) / payload_size; 336 337 uint32_t read_payloads = 338 (read_size + payload_size - 1) / payload_size; 339 340 uint32_t payloads_num = write_payloads + read_payloads; 341 342 if (!payloads_num) 343 return false; 344 345 if (link_is_in_aux_transaction_mode(ddc)) { 346 struct aux_payload payload; 347 348 payload.i2c_over_aux = true; 349 payload.address = address; 350 payload.reply = NULL; 351 payload.defer_delay = link_get_aux_defer_delay(ddc); 352 payload.write_status_update = false; 353 354 if (write_size != 0) { 355 payload.write = true; 356 /* should not set mot (middle of transaction) to 0 357 * if there are pending read payloads 358 */ 359 payload.mot = !(read_size == 0); 360 payload.length = write_size; 361 payload.data = write_buf; 362 363 success = submit_aux_command(ddc, &payload); 364 } 365 366 if (read_size != 0 && success) { 367 payload.write = false; 368 /* should set mot (middle of transaction) to 0 369 * since it is the last payload to send 370 */ 371 payload.mot = false; 372 payload.length = read_size; 373 payload.data = read_buf; 374 375 success = submit_aux_command(ddc, &payload); 376 } 377 } else { 378 struct i2c_command command = {0}; 379 struct i2c_payloads payloads; 380 381 if (!i2c_payloads_create(ddc->ctx, &payloads, payloads_num)) 382 return false; 383 384 command.payloads = i2c_payloads_get(&payloads); 385 command.number_of_payloads = 0; 386 command.engine = DDC_I2C_COMMAND_ENGINE; 387 command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz; 388 389 i2c_payloads_add( 390 &payloads, address, write_size, write_buf, true); 391 392 i2c_payloads_add( 393 &payloads, address, read_size, read_buf, false); 394 395 command.number_of_payloads = (uint8_t)i2c_payloads_get_count(&payloads); 396 397 success = dm_helpers_submit_i2c( 398 ddc->ctx, 399 ddc->link, 400 &command); 401 402 i2c_payloads_destroy(&payloads); 403 } 404 405 return success; 406 } 407 408 int link_aux_transfer_raw(struct ddc_service *ddc, 409 struct aux_payload *payload, 410 enum aux_return_code_type *operation_result) 411 { 412 return dce_aux_transfer_raw(ddc, payload, operation_result); 413 } 414 415 uint32_t link_get_fixed_vs_pe_retimer_write_address(struct dc_link *link) 416 { 417 uint32_t vendor_lttpr_write_address = 0xF004F; 418 uint8_t offset; 419 420 switch (link->dpcd_caps.lttpr_caps.phy_repeater_cnt) { 421 case 0x80: // 1 lttpr repeater 422 offset = 1; 423 break; 424 case 0x40: // 2 lttpr repeaters 425 offset = 2; 426 break; 427 case 0x20: // 3 lttpr repeaters 428 offset = 3; 429 break; 430 case 0x10: // 4 lttpr repeaters 431 offset = 4; 432 break; 433 case 0x08: // 5 lttpr repeaters 434 offset = 5; 435 break; 436 case 0x04: // 6 lttpr repeaters 437 offset = 6; 438 break; 439 case 0x02: // 7 lttpr repeaters 440 offset = 7; 441 break; 442 case 0x01: // 8 lttpr repeaters 443 offset = 8; 444 break; 445 default: 446 offset = 0xFF; 447 } 448 449 if (offset != 0xFF) { 450 vendor_lttpr_write_address += 451 ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); 452 } 453 return vendor_lttpr_write_address; 454 } 455 456 uint32_t link_get_fixed_vs_pe_retimer_read_address(struct dc_link *link) 457 { 458 return link_get_fixed_vs_pe_retimer_write_address(link) + 4; 459 } 460 461 bool link_configure_fixed_vs_pe_retimer(struct ddc_service *ddc, const uint8_t *data, uint32_t length) 462 { 463 struct aux_payload write_payload = { 464 .i2c_over_aux = false, 465 .write = true, 466 .address = link_get_fixed_vs_pe_retimer_write_address(ddc->link), 467 .length = length, 468 .data = (uint8_t *) data, 469 .reply = NULL, 470 .mot = I2C_MOT_UNDEF, 471 .write_status_update = false, 472 .defer_delay = 0, 473 }; 474 475 return link_aux_transfer_with_retries_no_mutex(ddc, 476 &write_payload); 477 } 478 479 bool link_query_fixed_vs_pe_retimer(struct ddc_service *ddc, uint8_t *data, uint32_t length) 480 { 481 struct aux_payload read_payload = { 482 .i2c_over_aux = false, 483 .write = false, 484 .address = link_get_fixed_vs_pe_retimer_read_address(ddc->link), 485 .length = length, 486 .data = data, 487 .reply = NULL, 488 .mot = I2C_MOT_UNDEF, 489 .write_status_update = false, 490 .defer_delay = 0, 491 }; 492 493 return link_aux_transfer_with_retries_no_mutex(ddc, 494 &read_payload); 495 } 496 497 bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc, 498 struct aux_payload *payload) 499 { 500 return dce_aux_transfer_with_retries(ddc, payload); 501 } 502 503 504 bool try_to_configure_aux_timeout(struct ddc_service *ddc, 505 uint32_t timeout) 506 { 507 bool result = false; 508 struct ddc *ddc_pin = ddc->ddc_pin; 509 510 if (((ddc->link->chip_caps & AMD_EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK) == AMD_EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && 511 !ddc->link->dc->debug.disable_fixed_vs_aux_timeout_wa && 512 ddc->ctx->dce_version == DCN_VERSION_3_1) { 513 /* Fixed VS workaround for AUX timeout */ 514 const uint32_t fixed_vs_address = 0xF004F; 515 const uint8_t fixed_vs_data[4] = {0x1, 0x22, 0x63, 0xc}; 516 517 core_link_write_dpcd(ddc->link, 518 fixed_vs_address, 519 fixed_vs_data, 520 sizeof(fixed_vs_data)); 521 522 timeout = 3072; 523 } 524 525 /* Do not try to access nonexistent DDC pin. */ 526 if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY) 527 return true; 528 529 if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) { 530 if (ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]->funcs->configure_timeout) { 531 ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]->funcs->configure_timeout(ddc, timeout); 532 result = true; 533 } 534 } else { 535 if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) { 536 ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout); 537 result = true; 538 } 539 540 } 541 return result; 542 } 543 544 struct ddc *get_ddc_pin(struct ddc_service *ddc_service) 545 { 546 return ddc_service->ddc_pin; 547 } 548 549 void write_scdc_data(struct ddc_service *ddc_service, 550 uint32_t pix_clk, 551 bool lte_340_scramble) 552 { 553 bool over_340_mhz = pix_clk > 340000 ? 1 : 0; 554 uint8_t slave_address = HDMI_SCDC_ADDRESS; 555 uint8_t offset = HDMI_SCDC_SINK_VERSION; 556 uint8_t sink_version = 0; 557 uint8_t write_buffer[2] = {0}; 558 /*Lower than 340 Scramble bit from SCDC caps*/ 559 560 if (ddc_service->link->local_sink && 561 (ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite || 562 !ddc_service->link->local_sink->edid_caps.scdc_present)) 563 return; 564 hdmi_frl_LTS_clear_Link_Setting(ddc_service); 565 hdmi_frl_LTS_clear_Update_flag(ddc_service); 566 567 link_query_ddc_data(ddc_service, slave_address, &offset, 568 sizeof(offset), &sink_version, sizeof(sink_version)); 569 if (sink_version == 1) { 570 /*Source Version = 1*/ 571 write_buffer[0] = HDMI_SCDC_SOURCE_VERSION; 572 write_buffer[1] = 1; 573 link_query_ddc_data(ddc_service, slave_address, 574 write_buffer, sizeof(write_buffer), NULL, 0); 575 /*Read Request from SCDC caps*/ 576 } 577 write_buffer[0] = HDMI_SCDC_TMDS_CONFIG; 578 579 if (over_340_mhz) { 580 write_buffer[1] = 3; 581 } else if (lte_340_scramble) { 582 write_buffer[1] = 1; 583 } else { 584 write_buffer[1] = 0; 585 } 586 link_query_ddc_data(ddc_service, slave_address, write_buffer, 587 sizeof(write_buffer), NULL, 0); 588 } 589 590 void read_scdc_data(struct ddc_service *ddc_service) 591 { 592 uint8_t slave_address = HDMI_SCDC_ADDRESS; 593 uint8_t offset = HDMI_SCDC_TMDS_CONFIG; 594 uint8_t tmds_config = 0; 595 596 if (ddc_service->link->local_sink && 597 ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite) 598 return; 599 600 link_query_ddc_data(ddc_service, slave_address, &offset, 601 sizeof(offset), &tmds_config, sizeof(tmds_config)); 602 if (tmds_config & 0x1) { 603 union hdmi_scdc_status_flags_data status_data = {0}; 604 uint8_t scramble_status = 0; 605 606 offset = HDMI_SCDC_SCRAMBLER_STATUS; 607 link_query_ddc_data(ddc_service, slave_address, 608 &offset, sizeof(offset), &scramble_status, 609 sizeof(scramble_status)); 610 offset = HDMI_SCDC_STATUS_FLAGS; 611 link_query_ddc_data(ddc_service, slave_address, 612 &offset, sizeof(offset), &status_data.byte, 613 sizeof(status_data.byte)); 614 } 615 } 616 void write_idcc_data(struct ddc_service *ddc_service, enum hdmi_idcc_scope idcc_scope, 617 uint8_t *write_buf, uint8_t offset, uint8_t write_len) 618 { 619 uint8_t slave_address = HDMI_IDCC_ADDRESS; 620 uint8_t idcc_header[5] = {0}; 621 uint8_t dummy_buf[1] = {0}; 622 uint8_t checksum = 0; 623 int i; 624 625 idcc_header[0] = HDMI_IDCC_MARKER0; 626 idcc_header[1] = HDMI_IDCC_MARKER1; 627 idcc_header[2] = (uint8_t)(HDMI_IDCC_MARKER2 | idcc_scope); 628 idcc_header[3] = offset; 629 idcc_header[4] = write_len; 630 631 /* Write the IDCC header */ 632 for (i = 0; i < sizeof(idcc_header); ++i) { 633 link_query_ddc_data(ddc_service, slave_address, 634 &idcc_header[i], 1, 635 &dummy_buf[0], 1); 636 checksum += idcc_header[i]; 637 } 638 639 /* Write the payload */ 640 for (i = 0; i < write_len; ++i) { 641 link_query_ddc_data(ddc_service, slave_address, 642 &write_buf[i], 1, 643 &dummy_buf[0], 1); 644 checksum += write_buf[i]; 645 } 646 647 /* Write the checksum */ 648 if (write_len > 0) { 649 checksum = 0xff - checksum + 1; 650 link_query_ddc_data(ddc_service, slave_address, 651 &checksum, 1, 652 &dummy_buf[0], 1); 653 } 654 } 655 656 int read_idcc_data(struct ddc_service *ddc_service, enum hdmi_idcc_scope idcc_scope, 657 uint8_t *read_buf, uint8_t offset, uint8_t read_len) 658 { 659 uint8_t slave_address = HDMI_IDCC_ADDRESS; 660 uint8_t idcc_header[5] = {0}; 661 uint8_t dummy_buf[1] = {0}; 662 uint8_t read_buf_local[6] = {0}; 663 uint8_t checksum = 0; 664 int i; 665 666 idcc_header[0] = HDMI_IDCC_MARKER0; 667 idcc_header[1] = HDMI_IDCC_MARKER1; 668 idcc_header[2] = (uint8_t)(HDMI_IDCC_MARKER2 | idcc_scope); 669 idcc_header[3] = offset; 670 idcc_header[4] = read_len; 671 672 /* Write the IDCC header */ 673 for (i = 0; i < sizeof(idcc_header); ++i) { 674 link_query_ddc_data(ddc_service, slave_address, 675 &idcc_header[i], 1, 676 &dummy_buf[0], 1); 677 checksum += idcc_header[i]; 678 } 679 680 /* Read the payload */ 681 if (read_len > 0) { 682 dummy_buf[0] = 0x01; 683 if (read_len > 5) 684 read_len = 5; 685 link_query_ddc_data(ddc_service, slave_address, 686 &dummy_buf[0], 1, 687 &read_buf_local[0], read_len + 1); 688 689 memcpy(read_buf, read_buf_local, read_len); 690 691 /* Check checksum */ 692 checksum = read_buf_local[read_len]; 693 for (i = 0; i < 5; ++i) 694 checksum += idcc_header[i]; 695 for (i = 0; i < read_len; ++i) 696 checksum += read_buf_local[i]; 697 if (checksum != 0) 698 return -1; 699 } 700 701 return read_len; 702 } 703