Commit af435e3f authored by Jacky Liao's avatar Jacky Liao Committed by Alex Deucher

drm/amd/display: Add I2C memory low power support

[Why]
The I2C memory blocks should be powered down when they are not in use.
This will reduce power consumption.

[How]
1. Write to I2C_LIGHT_SLEEP_FORCE to put memory in light sleep when
   released
2. Added a debug option to allow this behaviour to be turned off
Signed-off-by: default avatarJacky Liao <ziyu.liao@amd.com>
Acked-by: default avatarBindu Ramamurthy <bindu.r@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 65e870df
...@@ -419,6 +419,7 @@ struct dc_bw_validation_profile { ...@@ -419,6 +419,7 @@ struct dc_bw_validation_profile {
union mem_low_power_enable_options { union mem_low_power_enable_options {
struct { struct {
bool i2c: 1;
bool mpc: 1; bool mpc: 1;
bool optc: 1; bool optc: 1;
} bits; } bits;
......
...@@ -293,6 +293,14 @@ static bool setup_engine( ...@@ -293,6 +293,14 @@ static bool setup_engine(
{ {
uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE;
uint32_t reset_length = 0; uint32_t reset_length = 0;
if (dce_i2c_hw->ctx->dc->debug.enable_mem_low_power.bits.i2c) {
if (dce_i2c_hw->regs->DIO_MEM_PWR_CTRL) {
REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0);
REG_WAIT(DIO_MEM_PWR_STATUS, I2C_MEM_PWR_STATE, 0, 0, 5);
}
}
/* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/ /* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/
REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1); REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1);
...@@ -369,6 +377,10 @@ static void release_engine( ...@@ -369,6 +377,10 @@ static void release_engine(
REG_UPDATE_2(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1, REG_UPDATE_2(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1,
DC_I2C_SW_USE_I2C_REG_REQ, 0); DC_I2C_SW_USE_I2C_REG_REQ, 0);
if (dce_i2c_hw->ctx->dc->debug.enable_mem_low_power.bits.i2c) {
if (dce_i2c_hw->regs->DIO_MEM_PWR_CTRL)
REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1);
}
} }
struct dce_i2c_hw *acquire_i2c_hw_engine( struct dce_i2c_hw *acquire_i2c_hw_engine(
......
...@@ -95,6 +95,11 @@ enum { ...@@ -95,6 +95,11 @@ enum {
SR(DC_I2C_DATA),\ SR(DC_I2C_DATA),\
SR(MICROSECOND_TIME_BASE_DIV) SR(MICROSECOND_TIME_BASE_DIV)
#define I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id)\
I2C_HW_ENGINE_COMMON_REG_LIST(id),\
SR(DIO_MEM_PWR_CTRL),\
SR(DIO_MEM_PWR_STATUS)
#define I2C_SF(reg_name, field_name, post_fix)\ #define I2C_SF(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix .field_name = reg_name ## __ ## field_name ## post_fix
...@@ -179,6 +184,8 @@ struct dce_i2c_shift { ...@@ -179,6 +184,8 @@ struct dce_i2c_shift {
uint8_t XTAL_REF_DIV; uint8_t XTAL_REF_DIV;
uint8_t DC_I2C_DDC1_SEND_RESET_LENGTH; uint8_t DC_I2C_DDC1_SEND_RESET_LENGTH;
uint8_t DC_I2C_REG_RW_CNTL_STATUS; uint8_t DC_I2C_REG_RW_CNTL_STATUS;
uint8_t I2C_LIGHT_SLEEP_FORCE;
uint8_t I2C_MEM_PWR_STATE;
}; };
struct dce_i2c_mask { struct dce_i2c_mask {
...@@ -220,12 +227,19 @@ struct dce_i2c_mask { ...@@ -220,12 +227,19 @@ struct dce_i2c_mask {
uint32_t XTAL_REF_DIV; uint32_t XTAL_REF_DIV;
uint32_t DC_I2C_DDC1_SEND_RESET_LENGTH; uint32_t DC_I2C_DDC1_SEND_RESET_LENGTH;
uint32_t DC_I2C_REG_RW_CNTL_STATUS; uint32_t DC_I2C_REG_RW_CNTL_STATUS;
uint32_t I2C_LIGHT_SLEEP_FORCE;
uint32_t I2C_MEM_PWR_STATE;
}; };
#define I2C_COMMON_MASK_SH_LIST_DCN2(mask_sh)\ #define I2C_COMMON_MASK_SH_LIST_DCN2(mask_sh)\
I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh),\ I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh),\
I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH, mask_sh) I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH, mask_sh)
#define I2C_COMMON_MASK_SH_LIST_DCN30(mask_sh)\
I2C_COMMON_MASK_SH_LIST_DCN2(mask_sh),\
I2C_SF(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh),\
I2C_SF(DIO_MEM_PWR_STATUS, I2C_MEM_PWR_STATE, mask_sh)
struct dce_i2c_registers { struct dce_i2c_registers {
uint32_t SETUP; uint32_t SETUP;
uint32_t SPEED; uint32_t SPEED;
...@@ -239,6 +253,8 @@ struct dce_i2c_registers { ...@@ -239,6 +253,8 @@ struct dce_i2c_registers {
uint32_t DC_I2C_TRANSACTION3; uint32_t DC_I2C_TRANSACTION3;
uint32_t DC_I2C_DATA; uint32_t DC_I2C_DATA;
uint32_t MICROSECOND_TIME_BASE_DIV; uint32_t MICROSECOND_TIME_BASE_DIV;
uint32_t DIO_MEM_PWR_CTRL;
uint32_t DIO_MEM_PWR_STATUS;
}; };
enum dce_i2c_transaction_address_space { enum dce_i2c_transaction_address_space {
......
...@@ -933,7 +933,7 @@ static struct dce_aux *dcn30_aux_engine_create( ...@@ -933,7 +933,7 @@ static struct dce_aux *dcn30_aux_engine_create(
return &aux_engine->base; return &aux_engine->base;
} }
#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } #define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) }
static const struct dce_i2c_registers i2c_hw_regs[] = { static const struct dce_i2c_registers i2c_hw_regs[] = {
i2c_inst_regs(1), i2c_inst_regs(1),
...@@ -945,11 +945,11 @@ static const struct dce_i2c_registers i2c_hw_regs[] = { ...@@ -945,11 +945,11 @@ static const struct dce_i2c_registers i2c_hw_regs[] = {
}; };
static const struct dce_i2c_shift i2c_shifts = { static const struct dce_i2c_shift i2c_shifts = {
I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
}; };
static const struct dce_i2c_mask i2c_masks = { static const struct dce_i2c_mask i2c_masks = {
I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) I2C_COMMON_MASK_SH_LIST_DCN30(_MASK)
}; };
static struct dce_i2c_hw *dcn30_i2c_hw_create( static struct dce_i2c_hw *dcn30_i2c_hw_create(
......
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