diff options
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.patch | 173 |
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 + |