Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Handle I2C-over-AUX write channel status update

[Why]
When writing long AUX commands some sinks will respond will write status
update requiring source to read status.

[How]
When a write request is replied with data (AUX_ACK_M), retry a read of
write status to determine when the write is completed.

Reviewed-by: Martin Leung <Martin.Leung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Acked-by: Agustin Gutierrez <agustin.gutierrez@amd.com>
Signed-off-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Aric Cyr and committed by
Alex Deucher
8df219bb 1072461c

+44 -10
+2
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
··· 64 64 payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0; 65 65 payload.write = (msg->request & DP_AUX_I2C_READ) == 0; 66 66 payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0; 67 + payload.write_status_update = 68 + (msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; 67 69 payload.defer_delay = 0; 68 70 69 71 result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
+31 -3
drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
··· 534 534 static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) 535 535 { 536 536 if (payload->i2c_over_aux) { 537 + if (payload->write_status_update) { 538 + if (payload->mot) 539 + return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT; 540 + else 541 + return I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; 542 + } 537 543 if (payload->write) { 538 544 if (payload->mot) 539 545 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; 540 - return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; 546 + else 547 + return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; 541 548 } 542 549 if (payload->mot) 543 550 return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; 551 + 544 552 return I2CAUX_TRANSACTION_ACTION_I2C_READ; 545 553 } 546 554 if (payload->write) 547 555 return I2CAUX_TRANSACTION_ACTION_DP_WRITE; 556 + 548 557 return I2CAUX_TRANSACTION_ACTION_DP_READ; 549 558 } 550 559 ··· 707 698 aux_defer_retries = 0, 708 699 aux_i2c_defer_retries = 0, 709 700 aux_timeout_retries = 0, 710 - aux_invalid_reply_retries = 0; 701 + aux_invalid_reply_retries = 0, 702 + aux_ack_m_retries = 0; 711 703 712 704 if (ddc_pin) { 713 705 aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; ··· 768 758 aux_defer_retries, 769 759 AUX_MAX_RETRIES); 770 760 goto fail; 771 - } else { 761 + } else 772 762 udelay(300); 763 + } else if (payload->write && ret > 0) { 764 + /* sink requested more time to complete the write via AUX_ACKM */ 765 + if (++aux_ack_m_retries >= AUX_MAX_RETRIES) { 766 + DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, 767 + LOG_FLAG_Error_I2cAux, 768 + "dce_aux_transfer_with_retries: FAILURE: aux_ack_m_retries=%d >= AUX_MAX_RETRIES=%d", 769 + aux_ack_m_retries, 770 + AUX_MAX_RETRIES); 771 + goto fail; 773 772 } 773 + 774 + /* retry reading the write status until complete 775 + * NOTE: payload is modified here 776 + */ 777 + payload->write = false; 778 + payload->write_status_update = true; 779 + payload->length = 0; 780 + udelay(300); 781 + 774 782 } else 775 783 return true; 776 784 break;
+3
drivers/gpu/drm/amd/display/include/i2caux_interface.h
··· 41 41 * reset it to read data */ 42 42 bool write; 43 43 bool mot; 44 + bool write_status_update; 45 + 44 46 uint32_t address; 45 47 uint32_t length; 46 48 uint8_t *data; ··· 55 53 * zero means "use default value" 56 54 */ 57 55 uint32_t defer_delay; 56 + 58 57 }; 59 58 60 59 struct aux_command {