Commit f0922004 authored by Derek Lai's avatar Derek Lai Committed by Alex Deucher

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: default avatarDerek Lai <Derek.Lai@amd.com>
Reviewed-by: default avatarCharlene Liu <Charlene.Liu@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0bfb01ce
...@@ -149,6 +149,36 @@ static void process_channel_reply( ...@@ -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( static bool process_transaction(
struct dce_i2c_hw *dce_i2c_hw, struct dce_i2c_hw *dce_i2c_hw,
struct i2c_request_transaction_data *request) struct i2c_request_transaction_data *request)
...@@ -159,6 +189,11 @@ static bool process_transaction( ...@@ -159,6 +189,11 @@ static bool process_transaction(
bool last_transaction = false; bool last_transaction = false;
uint32_t value = 0; 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) || last_transaction = ((dce_i2c_hw->transaction_count == 3) ||
(request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) || (request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) ||
(request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)); (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ));
...@@ -294,27 +329,12 @@ static bool setup_engine( ...@@ -294,27 +329,12 @@ static bool setup_engine(
* Enable restart of SW I2C that was interrupted by HW * Enable restart of SW I2C that was interrupted by HW
* disable queuing of software while I2C is in use by HW * disable queuing of software while I2C is in use by HW
*/ */
REG_UPDATE_2(DC_I2C_ARBITRATION, REG_UPDATE(DC_I2C_ARBITRATION,
DC_I2C_NO_QUEUED_SW_GO, 0, DC_I2C_NO_QUEUED_SW_GO, 0);
DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL);
return true; 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( static void release_engine(
struct dce_i2c_hw *dce_i2c_hw) struct dce_i2c_hw *dce_i2c_hw)
{ {
...@@ -349,16 +369,6 @@ static void release_engine( ...@@ -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 dce_i2c_hw *acquire_i2c_hw_engine(
struct resource_pool *pool, struct resource_pool *pool,
struct ddc *ddc) struct ddc *ddc)
...@@ -456,6 +466,7 @@ static void submit_channel_request_hw( ...@@ -456,6 +466,7 @@ static void submit_channel_request_hw(
request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
return; return;
} }
reset_hw_engine(dce_i2c_hw);
execute_transaction(dce_i2c_hw); execute_transaction(dce_i2c_hw);
......
...@@ -84,6 +84,7 @@ enum { ...@@ -84,6 +84,7 @@ enum {
#define I2C_HW_ENGINE_COMMON_REG_LIST(id)\ #define I2C_HW_ENGINE_COMMON_REG_LIST(id)\
SRI(SETUP, DC_I2C_DDC, id),\ SRI(SETUP, DC_I2C_DDC, id),\
SRI(SPEED, DC_I2C_DDC, id),\ SRI(SPEED, DC_I2C_DDC, id),\
SRI(HW_STATUS, DC_I2C_DDC, id),\
SR(DC_I2C_ARBITRATION),\ SR(DC_I2C_ARBITRATION),\
SR(DC_I2C_CONTROL),\ SR(DC_I2C_CONTROL),\
SR(DC_I2C_SW_STATUS),\ SR(DC_I2C_SW_STATUS),\
...@@ -105,6 +106,7 @@ enum { ...@@ -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_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_TRANSACTION_DELAY, mask_sh),\
I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_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_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_SW_DONE_USING_I2C_REG, mask_sh),\
I2C_SF(DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, mask_sh),\ I2C_SF(DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, mask_sh),\
...@@ -146,6 +148,7 @@ struct dce_i2c_shift { ...@@ -146,6 +148,7 @@ struct dce_i2c_shift {
uint8_t DC_I2C_DDC1_DATA_DRIVE_SEL; uint8_t DC_I2C_DDC1_DATA_DRIVE_SEL;
uint8_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY; uint8_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
uint8_t DC_I2C_DDC1_INTRA_BYTE_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_DONE_USING_I2C_REG;
uint8_t DC_I2C_SW_USE_I2C_REG_REQ; uint8_t DC_I2C_SW_USE_I2C_REG_REQ;
uint8_t DC_I2C_NO_QUEUED_SW_GO; uint8_t DC_I2C_NO_QUEUED_SW_GO;
...@@ -185,6 +188,7 @@ struct dce_i2c_mask { ...@@ -185,6 +188,7 @@ struct dce_i2c_mask {
uint32_t DC_I2C_DDC1_DATA_DRIVE_SEL; uint32_t DC_I2C_DDC1_DATA_DRIVE_SEL;
uint32_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY; uint32_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY;
uint32_t DC_I2C_DDC1_INTRA_BYTE_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_DONE_USING_I2C_REG;
uint32_t DC_I2C_SW_USE_I2C_REG_REQ; uint32_t DC_I2C_SW_USE_I2C_REG_REQ;
uint32_t DC_I2C_NO_QUEUED_SW_GO; uint32_t DC_I2C_NO_QUEUED_SW_GO;
...@@ -219,6 +223,7 @@ struct dce_i2c_mask { ...@@ -219,6 +223,7 @@ struct dce_i2c_mask {
struct dce_i2c_registers { struct dce_i2c_registers {
uint32_t SETUP; uint32_t SETUP;
uint32_t SPEED; uint32_t SPEED;
uint32_t HW_STATUS;
uint32_t DC_I2C_ARBITRATION; uint32_t DC_I2C_ARBITRATION;
uint32_t DC_I2C_CONTROL; uint32_t DC_I2C_CONTROL;
uint32_t DC_I2C_SW_STATUS; uint32_t DC_I2C_SW_STATUS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment