static void release_engine( struct dce_i2c_hw *dce_i2c_hw) { bool safe_to_reset; /* Restore original HW engine speed */ set_speed(dce_i2c_hw, dce_i2c_hw->original_speed); /* Release I2C */ REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1); /* Reset HW engine */ { uint32_t i2c_sw_status = 0; REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); /* if used by SW, safe to reset */ safe_to_reset = (i2c_sw_status == 1); } if (safe_to_reset) REG_UPDATE_2(DC_I2C_CONTROL, DC_I2C_SOFT_RESET, 1, DC_I2C_SW_STATUS_RESET, 1); else REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1); /* HW I2c engine - clock gating feature */ if (!dce_i2c_hw->engine_keep_power_up_count) REG_UPDATE_N(SETUP, 1, FN(SETUP, DC_I2C_DDC1_ENABLE), 0); }
static void execute_transaction( struct dce_i2c_hw *dce_i2c_hw) { REG_UPDATE_N(SETUP, 5, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0); REG_UPDATE_5(DC_I2C_CONTROL, DC_I2C_SOFT_RESET, 0, DC_I2C_SW_STATUS_RESET, 0, DC_I2C_SEND_RESET, 0, DC_I2C_GO, 0, DC_I2C_TRANSACTION_COUNT, dce_i2c_hw->transaction_count - 1); /* start I2C transfer */ REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1); /* all transactions were executed and HW buffer became empty * (even though it actually happens when status becomes DONE) */ dce_i2c_hw->transaction_count = 0; dce_i2c_hw->buffer_used_bytes = 0; }
static bool setup_engine( struct dce_i2c_hw *dce_i2c_hw) { uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; if (dce_i2c_hw->setup_limit != 0) i2c_setup_limit = dce_i2c_hw->setup_limit; /* Program pin select */ REG_UPDATE_6(DC_I2C_CONTROL, DC_I2C_GO, 0, DC_I2C_SOFT_RESET, 0, DC_I2C_SEND_RESET, 0, DC_I2C_SW_STATUS_RESET, 1, DC_I2C_TRANSACTION_COUNT, 0, DC_I2C_DDC_SELECT, dce_i2c_hw->engine_id); /* Program time limit */ if (dce_i2c_hw->send_reset_length == 0) { /*pre-dcn*/ REG_UPDATE_N(SETUP, 2, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); } /* Program HW priority * set to High - interrupt software I2C at any time * 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); return true; }
static bool setup_engine( struct i2c_engine *i2c_engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); /* Program pin select */ REG_UPDATE_6( DC_I2C_CONTROL, DC_I2C_GO, 0, DC_I2C_SOFT_RESET, 0, DC_I2C_SEND_RESET, 0, DC_I2C_SW_STATUS_RESET, 1, DC_I2C_TRANSACTION_COUNT, 0, DC_I2C_DDC_SELECT, hw_engine->engine_id); /* Program time limit */ REG_UPDATE_N( SETUP, 2, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), I2C_SETUP_TIME_LIMIT, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); /* Program HW priority * set to High - interrupt software I2C at any time * 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); return true; }
static void set_speed( struct dce_i2c_hw *dce_i2c_hw, uint32_t speed) { if (speed) { if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL) REG_UPDATE_N(SPEED, 3, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), dce_i2c_hw->reference_frequency / speed, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1); else REG_UPDATE_N(SPEED, 2, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), dce_i2c_hw->reference_frequency / speed, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2); } }
static void set_speed( struct i2c_engine *i2c_engine, uint32_t speed) { struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); if (speed) { if (hw_engine->i2c_mask->DC_I2C_DDC1_START_STOP_TIMING_CNTL) REG_UPDATE_N( SPEED, 3, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1); else REG_UPDATE_N( SPEED, 2, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2); } }
static void disable_i2c_hw_engine( struct i2c_hw_engine_dce110 *hw_engine) { REG_UPDATE_N(SETUP, 1, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 0); }