From: Derek Lai <Derek.Lai@xxxxxxx> 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@xxxxxxx> Reviewed-by: Charlene Liu <Charlene.Liu@xxxxxxx> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@xxxxxxx> --- .../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 _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx