diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3707-drm-amd-display-refine-i2c-over-aux.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3707-drm-amd-display-refine-i2c-over-aux.patch | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3707-drm-amd-display-refine-i2c-over-aux.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3707-drm-amd-display-refine-i2c-over-aux.patch new file mode 100644 index 00000000..d2344ba1 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3707-drm-amd-display-refine-i2c-over-aux.patch @@ -0,0 +1,158 @@ +From 7284f93ec90184100341e9e0ea145ad800284482 Mon Sep 17 00:00:00 2001 +From: Lewis Huang <Lewis.Huang@amd.com> +Date: Wed, 7 Aug 2019 18:05:49 +0800 +Subject: [PATCH 3707/4256] 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> +--- + .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 87 +++++++++++++------ + .../gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 3 + + 2 files changed, 63 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +index 7fd2d1358f1b..f70137d67c82 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +@@ -494,7 +494,7 @@ bool dal_ddc_service_query_ddc_data( + uint8_t *read_buf, + uint32_t read_size) + { +- bool ret; ++ bool ret = false; + uint32_t payload_size = + dal_ddc_service_is_in_aux_transaction_mode(ddc) ? + DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE; +@@ -513,34 +513,32 @@ bool dal_ddc_service_query_ddc_data( + /*TODO: len of payload data for i2c and aux is uint8!!!!, + * but we want to read 256 over i2c!!!!*/ + if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { +- struct aux_payload write_payload = { +- .i2c_over_aux = 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 = { +- .i2c_over_aux = true, +- .write = false, +- .mot = false, +- .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); ++ struct aux_payload payload; ++ bool read_available = true; ++ ++ payload.i2c_over_aux = true; ++ payload.address = address; ++ payload.reply = NULL; ++ payload.defer_delay = get_defer_delay(ddc); ++ ++ if (write_size != 0) { ++ payload.write = true; ++ payload.mot = true; ++ payload.length = write_size; ++ payload.data = write_buf; ++ ++ ret = dal_ddc_submit_aux_command(ddc, &payload); ++ read_available = ret; ++ } + +- if (!ret) +- return false; ++ if (read_size != 0 && read_available) { ++ 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 { + struct i2c_payloads *payloads = + dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num); +@@ -571,6 +569,41 @@ bool dal_ddc_service_query_ddc_data( + 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 + * the given aux payload. This function does not perform + * retries or handle error states. The reply is returned +diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +index b1fab251c09b..7d35d03a2d43 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +@@ -95,6 +95,9 @@ bool dal_ddc_service_query_ddc_data( + uint8_t *read_buf, + 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, + struct aux_payload *payload, + enum aux_channel_operation_result *operation_result); +-- +2.17.1 + |