mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
drm/amd/display: refine i2c over aux
[Why] When user mode use i2c over aux through ADL or DDI, the function dal_ddc_service_query_ddc_data will be called. There are two issues. 1. When read/write length > 16byte, current always return false because the DEFAULT_AUX_MAX_DATA_SIZE != length. 2. When usermode only need to read data through i2c, driver will write mot = true at the same address and cause i2c sink confused. Therefore the following read command will get garbage. [How] 1. Add function dal_dcc_submit_aux_command to handle length > 16 byte. 2. Check read size and write size when query ddc data. Signed-off-by: Lewis Huang <Lewis.Huang@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
8ac64f0af5
commit
4fd99f67f3
2 changed files with 61 additions and 25 deletions
|
@ -496,7 +496,7 @@ bool dal_ddc_service_query_ddc_data(
|
||||||
uint8_t *read_buf,
|
uint8_t *read_buf,
|
||||||
uint32_t read_size)
|
uint32_t read_size)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret = false;
|
||||||
uint32_t payload_size =
|
uint32_t payload_size =
|
||||||
dal_ddc_service_is_in_aux_transaction_mode(ddc) ?
|
dal_ddc_service_is_in_aux_transaction_mode(ddc) ?
|
||||||
DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
|
DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
|
||||||
|
@ -515,34 +515,32 @@ bool dal_ddc_service_query_ddc_data(
|
||||||
/*TODO: len of payload data for i2c and aux is uint8!!!!,
|
/*TODO: len of payload data for i2c and aux is uint8!!!!,
|
||||||
* but we want to read 256 over i2c!!!!*/
|
* but we want to read 256 over i2c!!!!*/
|
||||||
if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
|
if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
|
||||||
struct aux_payload write_payload = {
|
struct aux_payload payload;
|
||||||
.i2c_over_aux = true,
|
bool read_available = true;
|
||||||
.write = true,
|
|
||||||
.mot = true,
|
|
||||||
.address = address,
|
|
||||||
.length = write_size,
|
|
||||||
.data = write_buf,
|
|
||||||
.reply = NULL,
|
|
||||||
.defer_delay = get_defer_delay(ddc),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct aux_payload read_payload = {
|
payload.i2c_over_aux = true;
|
||||||
.i2c_over_aux = true,
|
payload.address = address;
|
||||||
.write = false,
|
payload.reply = NULL;
|
||||||
.mot = false,
|
payload.defer_delay = get_defer_delay(ddc);
|
||||||
.address = address,
|
|
||||||
.length = read_size,
|
|
||||||
.data = read_buf,
|
|
||||||
.reply = NULL,
|
|
||||||
.defer_delay = get_defer_delay(ddc),
|
|
||||||
};
|
|
||||||
|
|
||||||
ret = dc_link_aux_transfer_with_retries(ddc, &write_payload);
|
if (write_size != 0) {
|
||||||
|
payload.write = true;
|
||||||
|
payload.mot = true;
|
||||||
|
payload.length = write_size;
|
||||||
|
payload.data = write_buf;
|
||||||
|
|
||||||
if (!ret)
|
ret = dal_ddc_submit_aux_command(ddc, &payload);
|
||||||
return false;
|
read_available = ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = dc_link_aux_transfer_with_retries(ddc, &read_payload);
|
if (read_size != 0 && read_available) {
|
||||||
|
payload.write = false;
|
||||||
|
payload.mot = false;
|
||||||
|
payload.length = read_size;
|
||||||
|
payload.data = read_buf;
|
||||||
|
|
||||||
|
ret = dal_ddc_submit_aux_command(ddc, &payload);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
struct i2c_payloads *payloads =
|
struct i2c_payloads *payloads =
|
||||||
dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num);
|
dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num);
|
||||||
|
@ -573,6 +571,41 @@ bool dal_ddc_service_query_ddc_data(
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dal_ddc_submit_aux_command(struct ddc_service *ddc,
|
||||||
|
struct aux_payload *payload)
|
||||||
|
{
|
||||||
|
uint8_t retrieved = 0;
|
||||||
|
bool ret = 0;
|
||||||
|
|
||||||
|
if (!ddc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!payload)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct aux_payload current_payload;
|
||||||
|
bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >
|
||||||
|
payload->length ? true : false;
|
||||||
|
|
||||||
|
current_payload.address = payload->address;
|
||||||
|
current_payload.data = &payload->data[retrieved];
|
||||||
|
current_payload.defer_delay = payload->defer_delay;
|
||||||
|
current_payload.i2c_over_aux = payload->i2c_over_aux;
|
||||||
|
current_payload.length = is_end_of_payload ?
|
||||||
|
payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE;
|
||||||
|
current_payload.mot = payload->mot ? payload->mot : !is_end_of_payload;
|
||||||
|
current_payload.reply = payload->reply;
|
||||||
|
current_payload.write = payload->write;
|
||||||
|
|
||||||
|
ret = dc_link_aux_transfer_with_retries(ddc, ¤t_payload);
|
||||||
|
|
||||||
|
retrieved += current_payload.length;
|
||||||
|
} while (retrieved < payload->length && ret == true);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* dc_link_aux_transfer_raw() - Attempt to transfer
|
/* dc_link_aux_transfer_raw() - Attempt to transfer
|
||||||
* the given aux payload. This function does not perform
|
* the given aux payload. This function does not perform
|
||||||
* retries or handle error states. The reply is returned
|
* retries or handle error states. The reply is returned
|
||||||
|
|
|
@ -95,6 +95,9 @@ bool dal_ddc_service_query_ddc_data(
|
||||||
uint8_t *read_buf,
|
uint8_t *read_buf,
|
||||||
uint32_t read_size);
|
uint32_t read_size);
|
||||||
|
|
||||||
|
bool dal_ddc_submit_aux_command(struct ddc_service *ddc,
|
||||||
|
struct aux_payload *payload);
|
||||||
|
|
||||||
int dc_link_aux_transfer_raw(struct ddc_service *ddc,
|
int dc_link_aux_transfer_raw(struct ddc_service *ddc,
|
||||||
struct aux_payload *payload,
|
struct aux_payload *payload,
|
||||||
enum aux_channel_operation_result *operation_result);
|
enum aux_channel_operation_result *operation_result);
|
||||||
|
|
Loading…
Add table
Reference in a new issue