aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch173
1 files changed, 173 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch b/common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch
new file mode 100644
index 00000000..66b934ff
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.19.8/2071-drm-amd-display-add-i2c_hw_Status-check-to-make-sure.patch
@@ -0,0 +1,173 @@
+From 82033037ad413326a3a1425f05d89b0c7abf8f73 Mon Sep 17 00:00:00 2001
+From: Derek Lai <Derek.Lai@amd.com>
+Date: Wed, 22 May 2019 14:49:23 +0800
+Subject: [PATCH 2071/2940] drm/amd/display: add i2c_hw_Status check to make
+ sure as HW I2c in use
+
+1. Add i2c_hw_Status check to make sure when HW i2c is in use.
+2. Don't reset HW engine in is_hw_busy() and instead do this in
+process_transaction() because SW i2c does not check if hw i2c is in use
+
+Signed-off-by: Derek Lai <Derek.Lai@amd.com>
+Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
+Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
+---
+ .../gpu/drm/amd/display/dc/dce/dce_i2c_hw.c | 65 +++++++++++--------
+ .../gpu/drm/amd/display/dc/dce/dce_i2c_hw.h | 5 ++
+ 2 files changed, 43 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
+index 526aab438374..7f2460caa2a6 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
+@@ -149,6 +149,36 @@ static void process_channel_reply(
+ }
+ }
+
++static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw)
++{
++ unsigned int arbitrate;
++ unsigned int i2c_hw_status;
++
++ REG_GET(HW_STATUS, DC_I2C_DDC1_HW_STATUS, &i2c_hw_status);
++ if (i2c_hw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW)
++ return false;
++
++ REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate);
++ if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY)
++ return false;
++
++ return true;
++}
++
++static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw)
++{
++ uint32_t i2c_sw_status = 0;
++
++ REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
++ if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
++ return false;
++
++ if (is_engine_available(dce_i2c_hw))
++ return false;
++
++ return true;
++}
++
+ static bool process_transaction(
+ struct dce_i2c_hw *dce_i2c_hw,
+ struct i2c_request_transaction_data *request)
+@@ -159,6 +189,11 @@ static bool process_transaction(
+ bool last_transaction = false;
+ uint32_t value = 0;
+
++ if (is_hw_busy(dce_i2c_hw)) {
++ request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
++ return false;
++ }
++
+ last_transaction = ((dce_i2c_hw->transaction_count == 3) ||
+ (request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) ||
+ (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ));
+@@ -294,27 +329,12 @@ static bool setup_engine(
+ * Enable restart of SW I2C that was interrupted by HW
+ * disable queuing of software while I2C is in use by HW
+ */
+- REG_UPDATE_2(DC_I2C_ARBITRATION,
+- DC_I2C_NO_QUEUED_SW_GO, 0,
+- DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL);
++ REG_UPDATE(DC_I2C_ARBITRATION,
++ DC_I2C_NO_QUEUED_SW_GO, 0);
+
+ return true;
+ }
+
+-static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw)
+-{
+- uint32_t i2c_sw_status = 0;
+-
+- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
+- if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
+- return false;
+-
+- reset_hw_engine(dce_i2c_hw);
+-
+- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
+- return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
+-}
+-
+ static void release_engine(
+ struct dce_i2c_hw *dce_i2c_hw)
+ {
+@@ -349,16 +369,6 @@ static void release_engine(
+
+ }
+
+-static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw)
+-{
+- unsigned int arbitrate;
+-
+- REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate);
+- if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY)
+- return false;
+- return true;
+-}
+-
+ struct dce_i2c_hw *acquire_i2c_hw_engine(
+ struct resource_pool *pool,
+ struct ddc *ddc)
+@@ -456,6 +466,7 @@ static void submit_channel_request_hw(
+ request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
+ return;
+ }
++ reset_hw_engine(dce_i2c_hw);
+
+ execute_transaction(dce_i2c_hw);
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
+index f718e3d396f2..a633632f625b 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
+@@ -84,6 +84,7 @@ enum {
+ #define I2C_HW_ENGINE_COMMON_REG_LIST(id)\
+ SRI(SETUP, DC_I2C_DDC, id),\
+ SRI(SPEED, DC_I2C_DDC, id),\
++ SRI(HW_STATUS, DC_I2C_DDC, id),\
+ SR(DC_I2C_ARBITRATION),\
+ SR(DC_I2C_CONTROL),\
+ SR(DC_I2C_SW_STATUS),\
+@@ -105,6 +106,7 @@ enum {
+ I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL, mask_sh),\
+ I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY, mask_sh),\
+ I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY, mask_sh),\
++ I2C_SF(DC_I2C_DDC1_HW_STATUS, DC_I2C_DDC1_HW_STATUS, mask_sh),\
+ I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, mask_sh),\
+ I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, mask_sh),\
+ I2C_SF(DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, mask_sh),\
+@@ -146,6 +148,7 @@ struct dce_i2c_shift {
+ uint8_t DC_I2C_DDC1_DATA_DRIVE_SEL;
+ uint8_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
+ uint8_t DC_I2C_DDC1_INTRA_BYTE_DELAY;
++ uint8_t DC_I2C_DDC1_HW_STATUS;
+ uint8_t DC_I2C_SW_DONE_USING_I2C_REG;
+ uint8_t DC_I2C_SW_USE_I2C_REG_REQ;
+ uint8_t DC_I2C_NO_QUEUED_SW_GO;
+@@ -185,6 +188,7 @@ struct dce_i2c_mask {
+ uint32_t DC_I2C_DDC1_DATA_DRIVE_SEL;
+ uint32_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
+ uint32_t DC_I2C_DDC1_INTRA_BYTE_DELAY;
++ uint32_t DC_I2C_DDC1_HW_STATUS;
+ uint32_t DC_I2C_SW_DONE_USING_I2C_REG;
+ uint32_t DC_I2C_SW_USE_I2C_REG_REQ;
+ uint32_t DC_I2C_NO_QUEUED_SW_GO;
+@@ -219,6 +223,7 @@ struct dce_i2c_mask {
+ struct dce_i2c_registers {
+ uint32_t SETUP;
+ uint32_t SPEED;
++ uint32_t HW_STATUS;
+ uint32_t DC_I2C_ARBITRATION;
+ uint32_t DC_I2C_CONTROL;
+ uint32_t DC_I2C_SW_STATUS;
+--
+2.17.1
+