aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/4908-drm-amd-display-Break-out-function-to-simply-read-au.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/4908-drm-amd-display-Break-out-function-to-simply-read-au.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/4908-drm-amd-display-Break-out-function-to-simply-read-au.patch200
1 files changed, 200 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/4908-drm-amd-display-Break-out-function-to-simply-read-au.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/4908-drm-amd-display-Break-out-function-to-simply-read-au.patch
new file mode 100644
index 00000000..73a18a5b
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/4908-drm-amd-display-Break-out-function-to-simply-read-au.patch
@@ -0,0 +1,200 @@
+From 462e24fa4f1c1af6bd5ee845d2f757fcd1b8dec9 Mon Sep 17 00:00:00 2001
+From: Harry Wentland <harry.wentland@amd.com>
+Date: Tue, 8 May 2018 16:28:31 -0400
+Subject: [PATCH 4908/5725] drm/amd/display: Break out function to simply read
+ aux reply
+
+DRM's DP helpers take care of dealing with the error code for us. In
+order not to step on each other's toes we'll need to be able to simply
+read auch channel replies without further logic based on return values.
+
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com>
+Acked-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h | 6 ++
+ .../display/dc/i2caux/dce110/aux_engine_dce110.c | 119 ++++++++++++---------
+ 2 files changed, 76 insertions(+), 49 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h
+index b01488f..c33a289 100644
+--- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h
++++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h
+@@ -44,6 +44,12 @@ struct aux_engine_funcs {
+ void (*process_channel_reply)(
+ struct aux_engine *engine,
+ struct aux_reply_transaction_data *reply);
++ int (*read_channel_reply)(
++ struct aux_engine *engine,
++ uint32_t size,
++ uint8_t *buffer,
++ uint8_t *reply_result,
++ uint32_t *sw_status);
+ enum aux_channel_operation_result (*get_channel_status)(
+ struct aux_engine *engine,
+ uint8_t *returned_bytes);
+diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c
+index 2b927f2..1f39406 100644
+--- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c
++++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c
+@@ -275,61 +275,92 @@ static void submit_channel_request(
+ REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
+ }
+
+-static void process_channel_reply(
+- struct aux_engine *engine,
+- struct aux_reply_transaction_data *reply)
++static int read_channel_reply(struct aux_engine *engine, uint32_t size,
++ uint8_t *buffer, uint8_t *reply_result,
++ uint32_t *sw_status)
+ {
+ struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
++ uint32_t bytes_replied;
++ uint32_t reply_result_32;
+
+- /* Need to do a read to get the number of bytes to process
+- * Alternatively, this information can be passed -
+- * but that causes coupling which isn't good either. */
++ *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
++ &bytes_replied);
+
+- uint32_t bytes_replied;
+- uint32_t value;
++ /* In case HPD is LOW, exit AUX transaction */
++ if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
++ return -1;
+
+- value = REG_GET(AUX_SW_STATUS,
+- AUX_SW_REPLY_BYTE_COUNT, &bytes_replied);
++ /* Need at least the status byte */
++ if (!bytes_replied)
++ return -1;
+
+- /* in case HPD is LOW, exit AUX transaction */
+- if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
+- reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
+- return;
+- }
++ REG_UPDATE_1BY1_3(AUX_SW_DATA,
++ AUX_SW_INDEX, 0,
++ AUX_SW_AUTOINCREMENT_DISABLE, 1,
++ AUX_SW_DATA_RW, 1);
++
++ REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
++ *reply_result = (uint8_t)reply_result_32;
+
+- if (bytes_replied) {
+- uint32_t reply_result;
++ if (reply_result_32 >> 4 == 0) { /* ACK */
++ uint32_t i = 0;
+
+- REG_UPDATE_1BY1_3(AUX_SW_DATA,
+- AUX_SW_INDEX, 0,
+- AUX_SW_AUTOINCREMENT_DISABLE, 1,
+- AUX_SW_DATA_RW, 1);
++ /* First byte was already used to get the command status */
++ --bytes_replied;
+
+- REG_GET(AUX_SW_DATA,
+- AUX_SW_DATA, &reply_result);
++ /* Do not overflow buffer */
++ if (bytes_replied > size)
++ return -1;
+
+- reply_result = reply_result >> 4;
++ while (i < bytes_replied) {
++ uint32_t aux_sw_data_val;
+
+- switch (reply_result) {
+- case 0: /* ACK */ {
+- uint32_t i = 0;
++ REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
++ buffer[i] = aux_sw_data_val;
++ ++i;
++ }
+
+- /* first byte was already used
+- * to get the command status */
+- --bytes_replied;
++ return i;
++ }
++
++ return 0;
++}
++
++static void process_channel_reply(
++ struct aux_engine *engine,
++ struct aux_reply_transaction_data *reply)
++{
++ int bytes_replied;
++ uint8_t reply_result;
++ uint32_t sw_status;
+
+- while (i < bytes_replied) {
+- uint32_t aux_sw_data_val;
++ bytes_replied = read_channel_reply(engine, reply->length, reply->data,
++ &reply_result, &sw_status);
+
+- REG_GET(AUX_SW_DATA,
+- AUX_SW_DATA, &aux_sw_data_val);
++ /* in case HPD is LOW, exit AUX transaction */
++ if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
++ reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
++ return;
++ }
+
+- reply->data[i] = aux_sw_data_val;
+- ++i;
+- }
++ if (bytes_replied < 0) {
++ /* Need to handle an error case...
++ * Hopefully, upper layer function won't call this function if
++ * the number of bytes in the reply was 0, because there was
++ * surely an error that was asserted that should have been
++ * handled for hot plug case, this could happens
++ */
++ if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
++ reply->status = AUX_TRANSACTION_REPLY_INVALID;
++ ASSERT_CRITICAL(false);
++ return;
++ }
++ } else {
++ reply_result = reply_result >> 4;
+
++ switch (reply_result) {
++ case 0: /* ACK */
+ reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
+- }
+ break;
+ case 1: /* NACK */
+ reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
+@@ -346,17 +377,6 @@ static void process_channel_reply(
+ default:
+ reply->status = AUX_TRANSACTION_REPLY_INVALID;
+ }
+- } else {
+- /* Need to handle an error case...
+- * hopefully, upper layer function won't call this function
+- * if the number of bytes in the reply was 0
+- * because there was surely an error that was asserted
+- * that should have been handled
+- * for hot plug case, this could happens*/
+- if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
+- reply->status = AUX_TRANSACTION_REPLY_INVALID;
+- ASSERT_CRITICAL(false);
+- }
+ }
+ }
+
+@@ -427,6 +447,7 @@ static const struct aux_engine_funcs aux_engine_funcs = {
+ .acquire_engine = acquire_engine,
+ .submit_channel_request = submit_channel_request,
+ .process_channel_reply = process_channel_reply,
++ .read_channel_reply = read_channel_reply,
+ .get_channel_status = get_channel_status,
+ .is_engine_available = is_engine_available,
+ };
+--
+2.7.4
+