diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1075-drm-amd-display-Switch-ddc-to-new-aux-interface.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1075-drm-amd-display-Switch-ddc-to-new-aux-interface.patch | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1075-drm-amd-display-Switch-ddc-to-new-aux-interface.patch b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1075-drm-amd-display-Switch-ddc-to-new-aux-interface.patch new file mode 100644 index 00000000..cf165c1b --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux-4.19/linux-yocto-4.19.8/1075-drm-amd-display-Switch-ddc-to-new-aux-interface.patch @@ -0,0 +1,419 @@ +From 0b1b8d4167395baef1260ac57f4ac14b981b4498 Mon Sep 17 00:00:00 2001 +From: David Francis <David.Francis@amd.com> +Date: Thu, 29 Nov 2018 14:36:25 -0500 +Subject: [PATCH 1075/2940] drm/amd/display: Switch ddc to new aux interface + +[Why] +The old aux interface goes through i2caux and the aux_engine +and engine function pointers. The multiple layers of indirection +make it hard to tell waht is happening. The aux algorithm +does not need to be this complicated: attempt to submit the +request. If you get an ack (reply = 0), stop. Otherwise, +retry, up to 7 times. + +[How] +Add a new helper function in dce_aux that performs aux retries + +Move the plumbing of the aux calling code into dce_aux + +Add functions in ddc that redirect directly to dce_aux + +Make all aux calls use these functions + +Signed-off-by: David Francis <David.Francis@amd.com> +Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> +Acked-by: Leo Li <sunpeng.li@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 175 +++--------------- + drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 99 ++++++++++ + drivers/gpu/drm/amd/display/dc/dce/dce_aux.h | 6 + + .../gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 12 +- + 4 files changed, 137 insertions(+), 155 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 5ac65737a1e8..a343b8b6f7fb 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 +@@ -34,6 +34,7 @@ + #include "core_types.h" + #include "dc_link_ddc.h" + #include "aux_engine.h" ++#include "dce/dce_aux.h" + + #define AUX_POWER_UP_WA_DELAY 500 + #define I2C_OVER_AUX_DEFER_WA_DELAY 70 +@@ -164,43 +165,6 @@ static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p) + + } + +-static struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count) +-{ +- struct aux_payloads *payloads; +- +- payloads = kzalloc(sizeof(struct aux_payloads), GFP_KERNEL); +- +- if (!payloads) +- return NULL; +- +- if (dal_vector_construct( +- &payloads->payloads, ctx, count, sizeof(struct aux_payload))) +- return payloads; +- +- kfree(payloads); +- return NULL; +-} +- +-static struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p) +-{ +- return (struct aux_payload *)p->payloads.container; +-} +- +-static uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p) +-{ +- return p->payloads.count; +-} +- +-static void dal_ddc_aux_payloads_destroy(struct aux_payloads **p) +-{ +- if (!p || !*p) +- return; +- +- dal_vector_destruct(&(*p)->payloads); +- kfree(*p); +- *p = NULL; +-} +- + #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) + + void dal_ddc_i2c_payloads_add( +@@ -224,32 +188,6 @@ void dal_ddc_i2c_payloads_add( + + } + +-void dal_ddc_aux_payloads_add( +- struct aux_payloads *payloads, +- uint32_t address, +- uint32_t len, +- uint8_t *data, +- bool write, +- bool mot, +- uint32_t defer_delay) +-{ +- uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE; +- uint32_t pos; +- +- for (pos = 0; pos < len; pos += payload_size) { +- struct aux_payload payload = { +- .i2c_over_aux = true, +- .write = write, +- .address = address, +- .length = DDC_MIN(payload_size, len - pos), +- .data = data + pos, +- .reply = NULL, +- .mot = mot, +- .defer_delay = defer_delay}; +- dal_vector_append(&payloads->payloads, &payload); +- } +-} +- + static void construct( + struct ddc_service *ddc_service, + struct ddc_service_init_data *init_data) +@@ -578,32 +516,34 @@ 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_payloads *payloads = +- dal_ddc_aux_payloads_create(ddc->ctx, payloads_num); +- +- struct aux_command command = { +- .payloads = dal_ddc_aux_payloads_get(payloads), +- .number_of_payloads = 0, ++ 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), +- .max_defer_write_retry = 0 }; ++ }; + +- dal_ddc_aux_payloads_add( +- payloads, address, write_size, write_buf, true, true, get_defer_delay(ddc)); +- +- dal_ddc_aux_payloads_add( +- payloads, address, read_size, read_buf, false, false, get_defer_delay(ddc)); +- +- command.number_of_payloads = +- dal_ddc_aux_payloads_get_count(payloads); ++ 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 = dal_i2caux_submit_aux_command( +- ddc->ctx->i2caux, +- ddc->ddc_pin, +- &command); ++ ret = dc_link_aux_transfer_with_retries(ddc, &write_payload); + +- dal_ddc_aux_payloads_destroy(&payloads); ++ if (!ret) ++ return false; + ++ ret = dc_link_aux_transfer_with_retries(ddc, &read_payload); + } else { + struct i2c_payloads *payloads = + dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num); +@@ -634,73 +574,16 @@ bool dal_ddc_service_query_ddc_data( + return ret; + } + +-static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) ++int dc_link_aux_transfer(struct ddc_service *ddc, ++ struct aux_payload *payload) + { +- if (payload->i2c_over_aux) { +- if (payload->write) { +- if (payload->mot) +- return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; +- return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; +- } +- if (payload->mot) +- return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; +- return I2CAUX_TRANSACTION_ACTION_I2C_READ; +- } +- if (payload->write) +- return I2CAUX_TRANSACTION_ACTION_DP_WRITE; +- return I2CAUX_TRANSACTION_ACTION_DP_READ; ++ return dce_aux_transfer(ddc, payload); + } + +-int dc_link_aux_transfer(struct ddc_service *ddc, ++bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, + struct aux_payload *payload) + { +- struct ddc *ddc_pin = ddc->ddc_pin; +- struct aux_engine *aux_engine; +- enum aux_channel_operation_result operation_result; +- struct aux_request_transaction_data aux_req; +- struct aux_reply_transaction_data aux_rep; +- uint8_t returned_bytes = 0; +- int res = -1; +- uint32_t status; +- +- memset(&aux_req, 0, sizeof(aux_req)); +- memset(&aux_rep, 0, sizeof(aux_rep)); +- +- aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; +- aux_engine->funcs->acquire(aux_engine, ddc_pin); +- +- if (payload->i2c_over_aux) +- aux_req.type = AUX_TRANSACTION_TYPE_I2C; +- else +- aux_req.type = AUX_TRANSACTION_TYPE_DP; +- +- aux_req.action = i2caux_action_from_payload(payload); +- +- aux_req.address = payload->address; +- aux_req.delay = payload->defer_delay * 10; +- aux_req.length = payload->length; +- aux_req.data = payload->data; +- +- aux_engine->funcs->submit_channel_request(aux_engine, &aux_req); +- operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes); +- +- switch (operation_result) { +- case AUX_CHANNEL_OPERATION_SUCCEEDED: +- res = aux_engine->funcs->read_channel_reply(aux_engine, payload->length, +- payload->data, payload->reply, +- &status); +- break; +- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: +- res = 0; +- break; +- case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: +- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: +- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: +- res = -1; +- break; +- } +- aux_engine->funcs->release_engine(aux_engine); +- return res; ++ return dce_aux_transfer_with_retries(ddc, payload); + } + + /*test only function*/ +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +index 760bc5cc329d..566061529c58 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +@@ -24,6 +24,7 @@ + */ + + #include "dm_services.h" ++#include "core_types.h" + #include "dce_aux.h" + #include "dce/dce_11_0_sh_mask.h" + +@@ -936,3 +937,101 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng + return &aux_engine110->base; + } + ++static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) ++{ ++ if (payload->i2c_over_aux) { ++ if (payload->write) { ++ if (payload->mot) ++ return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; ++ return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; ++ } ++ if (payload->mot) ++ return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; ++ return I2CAUX_TRANSACTION_ACTION_I2C_READ; ++ } ++ if (payload->write) ++ return I2CAUX_TRANSACTION_ACTION_DP_WRITE; ++ return I2CAUX_TRANSACTION_ACTION_DP_READ; ++} ++ ++int dce_aux_transfer(struct ddc_service *ddc, ++ struct aux_payload *payload) ++{ ++ struct ddc *ddc_pin = ddc->ddc_pin; ++ struct aux_engine *aux_engine; ++ enum aux_channel_operation_result operation_result; ++ struct aux_request_transaction_data aux_req; ++ struct aux_reply_transaction_data aux_rep; ++ uint8_t returned_bytes = 0; ++ int res = -1; ++ uint32_t status; ++ ++ memset(&aux_req, 0, sizeof(aux_req)); ++ memset(&aux_rep, 0, sizeof(aux_rep)); ++ ++ aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; ++ aux_engine->funcs->acquire(aux_engine, ddc_pin); ++ ++ if (payload->i2c_over_aux) ++ aux_req.type = AUX_TRANSACTION_TYPE_I2C; ++ else ++ aux_req.type = AUX_TRANSACTION_TYPE_DP; ++ ++ aux_req.action = i2caux_action_from_payload(payload); ++ ++ aux_req.address = payload->address; ++ aux_req.delay = payload->defer_delay * 10; ++ aux_req.length = payload->length; ++ aux_req.data = payload->data; ++ ++ aux_engine->funcs->submit_channel_request(aux_engine, &aux_req); ++ operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes); ++ ++ switch (operation_result) { ++ case AUX_CHANNEL_OPERATION_SUCCEEDED: ++ res = aux_engine->funcs->read_channel_reply(aux_engine, payload->length, ++ payload->data, payload->reply, ++ &status); ++ break; ++ case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: ++ res = 0; ++ break; ++ case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: ++ case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: ++ case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: ++ res = -1; ++ break; ++ } ++ aux_engine->funcs->release_engine(aux_engine); ++ return res; ++} ++ ++#define AUX_RETRY_MAX 7 ++ ++bool dce_aux_transfer_with_retries(struct ddc_service *ddc, ++ struct aux_payload *payload) ++{ ++ int i, ret = 0; ++ uint8_t reply; ++ bool payload_reply = true; ++ ++ if (!payload->reply) { ++ payload_reply = false; ++ payload->reply = &reply; ++ } ++ ++ for (i = 0; i < AUX_RETRY_MAX; i++) { ++ ret = dce_aux_transfer(ddc, payload); ++ ++ if (ret >= 0) { ++ if (*payload->reply == 0) { ++ if (!payload_reply) ++ payload->reply = NULL; ++ return true; ++ } ++ } ++ ++ msleep(1); ++ } ++ return false; ++} +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +index f7caab85dc80..990e7c7e191e 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +@@ -108,4 +108,10 @@ void dce110_engine_destroy(struct aux_engine **engine); + bool dce110_aux_engine_acquire( + struct aux_engine *aux_engine, + struct ddc *ddc); ++ ++int dce_aux_transfer(struct ddc_service *ddc, ++ struct aux_payload *cmd); ++ ++bool dce_aux_transfer_with_retries(struct ddc_service *ddc, ++ struct aux_payload *cmd); + #endif +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 b609cd886455..16fd4dc6c4dd 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 +@@ -64,15 +64,6 @@ void dal_ddc_i2c_payloads_add( + uint8_t *data, + bool write); + +-void dal_ddc_aux_payloads_add( +- struct aux_payloads *payloads, +- uint32_t address, +- uint32_t len, +- uint8_t *data, +- bool write, +- bool mot, +- uint32_t defer_delay); +- + struct ddc_service_init_data { + struct graphics_object_id id; + struct dc_context *ctx; +@@ -107,6 +98,9 @@ bool dal_ddc_service_query_ddc_data( + int dc_link_aux_transfer(struct ddc_service *ddc, + struct aux_payload *payload); + ++bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, ++ struct aux_payload *payload); ++ + void dal_ddc_service_write_scdc_data( + struct ddc_service *ddc_service, + uint32_t pix_clk, +-- +2.17.1 + |