Commit 4fd99f67 authored by Lewis Huang's avatar Lewis Huang Committed by Alex Deucher

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: default avatarLewis Huang <Lewis.Huang@amd.com>
Reviewed-by: default avatarCharlene Liu <Charlene.Liu@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8ac64f0a
...@@ -496,7 +496,7 @@ bool dal_ddc_service_query_ddc_data( ...@@ -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( ...@@ -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, payload.i2c_over_aux = true;
.address = address, payload.address = address;
.length = write_size, payload.reply = NULL;
.data = write_buf, payload.defer_delay = get_defer_delay(ddc);
.reply = NULL,
.defer_delay = get_defer_delay(ddc), if (write_size != 0) {
}; payload.write = true;
payload.mot = true;
struct aux_payload read_payload = { payload.length = write_size;
.i2c_over_aux = true, payload.data = write_buf;
.write = false,
.mot = false, ret = dal_ddc_submit_aux_command(ddc, &payload);
.address = address, read_available = ret;
.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 (!ret) if (read_size != 0 && read_available) {
return false; payload.write = false;
payload.mot = false;
payload.length = read_size;
payload.data = read_buf;
ret = dc_link_aux_transfer_with_retries(ddc, &read_payload); 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( ...@@ -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, &current_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( ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment