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

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

[How]
1. Set ODM_MEM_UNASSIGNED_PWR_MODE to shutdown memory when unassigned
2. Set ODM_MEM_VBLANK_PWR_MODE to light sleep mode when in vblank
3. Added a debug option to allow this behaviour to be turned off
4. Restructured debug options to use a bitfield in a way that's more clear

Signed-off-by: Jacky Liao <ziyu.liao@amd.com>
Reviewed-by: Eric Yang <eric.yang2@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Jacky Liao
2020-10-15 17:42:16 -04:00
committed by Alex Deucher
parent 91bda9e9d2
commit cae78e0331
4 changed files with 32 additions and 10 deletions

View File

@@ -414,6 +414,14 @@ struct dc_bw_validation_profile {
} \ } \
} }
union mem_low_power_enable_options {
struct {
bool mpc: 1;
bool optc: 1;
} bits;
uint32_t u32All;
};
struct dc_debug_options { struct dc_debug_options {
enum visual_confirm visual_confirm; enum visual_confirm visual_confirm;
bool sanity_checks; bool sanity_checks;
@@ -506,7 +514,7 @@ struct dc_debug_options {
bool disable_dsc; bool disable_dsc;
bool enable_dram_clock_change_one_display_vactive; bool enable_dram_clock_change_one_display_vactive;
bool force_ignore_link_settings; bool force_ignore_link_settings;
bool enable_mpc_mem_powerdown: 1; union mem_low_power_enable_options enable_mem_low_power;
}; };
struct dc_debug_data { struct dc_debug_data {

View File

@@ -607,6 +607,10 @@ struct dce_hwseq_registers {
uint32_t MC_VM_XGMI_LFB_CNTL; uint32_t MC_VM_XGMI_LFB_CNTL;
uint32_t AZALIA_AUDIO_DTO; uint32_t AZALIA_AUDIO_DTO;
uint32_t AZALIA_CONTROLLER_CLOCK_GATING; uint32_t AZALIA_CONTROLLER_CLOCK_GATING;
#if defined(CONFIG_DRM_AMD_DC_DCN3_0)
uint32_t HPO_TOP_CLOCK_CONTROL;
uint32_t ODM_MEM_PWR_CTRL3;
#endif
}; };
/* set field name */ /* set field name */
#define HWS_SF(blk_name, reg_name, field_name, post_fix)\ #define HWS_SF(blk_name, reg_name, field_name, post_fix)\
@@ -845,7 +849,9 @@ struct dce_hwseq_registers {
#if defined(CONFIG_DRM_AMD_DC_DCN3_0) #if defined(CONFIG_DRM_AMD_DC_DCN3_0)
#define HWSEQ_DCN30_MASK_SH_LIST(mask_sh)\ #define HWSEQ_DCN30_MASK_SH_LIST(mask_sh)\
HWSEQ_DCN2_MASK_SH_LIST(mask_sh), \ HWSEQ_DCN2_MASK_SH_LIST(mask_sh), \
HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh) HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \
HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \
HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh)
#endif #endif
#if defined(CONFIG_DRM_AMD_DC_DCN3_01) #if defined(CONFIG_DRM_AMD_DC_DCN3_01)
@@ -1059,7 +1065,9 @@ struct dce_hwseq_registers {
type D2VGA_MODE_ENABLE; \ type D2VGA_MODE_ENABLE; \
type D3VGA_MODE_ENABLE; \ type D3VGA_MODE_ENABLE; \
type D4VGA_MODE_ENABLE; \ type D4VGA_MODE_ENABLE; \
type AZALIA_AUDIO_DTO_MODULE; type AZALIA_AUDIO_DTO_MODULE; \
type ODM_MEM_UNASSIGNED_PWR_MODE; \
type ODM_MEM_VBLANK_PWR_MODE;
#if defined(CONFIG_DRM_AMD_DC_DCN3_0) #if defined(CONFIG_DRM_AMD_DC_DCN3_0)
#define HWSEQ_DCN3_REG_FIELD_LIST(type) \ #define HWSEQ_DCN3_REG_FIELD_LIST(type) \

View File

@@ -462,6 +462,12 @@ void dcn30_init_hw(struct dc *dc)
hws->funcs.disable_vga(dc->hwseq); hws->funcs.disable_vga(dc->hwseq);
} }
// Set default OPTC memory power states
if (dc->debug.enable_mem_low_power.bits.optc) {
// Shutdown when unassigned and light sleep in VBLANK
REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
}
if (dc->ctx->dc_bios->fw_info_valid) { if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz =
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;

View File

@@ -143,7 +143,7 @@ static void mpc3_power_on_ogam_lut(
{ {
struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc);
if (mpc->ctx->dc->debug.enable_mpc_mem_powerdown) { if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
// Force power on // Force power on
REG_UPDATE(MPCC_MEM_PWR_CTRL[mpcc_id], MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0); REG_UPDATE(MPCC_MEM_PWR_CTRL[mpcc_id], MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0);
// Wait for confirmation when powering on // Wait for confirmation when powering on
@@ -369,7 +369,7 @@ void mpc3_set_output_gamma(
REG_UPDATE(MPCC_OGAM_CONTROL[mpcc_id], REG_UPDATE(MPCC_OGAM_CONTROL[mpcc_id],
MPCC_OGAM_SELECT, next_mode == LUT_RAM_A ? 0:1); MPCC_OGAM_SELECT, next_mode == LUT_RAM_A ? 0:1);
if (mpc->ctx->dc->debug.enable_mpc_mem_powerdown) if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
mpc3_power_on_ogam_lut(mpc, mpcc_id, false); mpc3_power_on_ogam_lut(mpc, mpcc_id, false);
} }
@@ -818,7 +818,7 @@ static void mpc3_power_on_shaper_3dlut(
REG_SET(MPC_RMU_MEM_PWR_CTRL, 0, REG_SET(MPC_RMU_MEM_PWR_CTRL, 0,
MPC_RMU0_MEM_PWR_DIS, power_on == true ? 1:0); MPC_RMU0_MEM_PWR_DIS, power_on == true ? 1:0);
/* wait for memory to fully power up */ /* wait for memory to fully power up */
if (power_on && mpc->ctx->dc->debug.enable_mpc_mem_powerdown) { if (power_on && mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU0_SHAPER_MEM_PWR_STATE, 0, 1, max_retries); REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU0_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU0_3DLUT_MEM_PWR_STATE, 0, 1, max_retries); REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU0_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
} }
@@ -829,7 +829,7 @@ static void mpc3_power_on_shaper_3dlut(
} else if (rmu_idx == 1) { } else if (rmu_idx == 1) {
REG_SET(MPC_RMU_MEM_PWR_CTRL, 0, REG_SET(MPC_RMU_MEM_PWR_CTRL, 0,
MPC_RMU1_MEM_PWR_DIS, power_on == true ? 1:0); MPC_RMU1_MEM_PWR_DIS, power_on == true ? 1:0);
if (power_on && mpc->ctx->dc->debug.enable_mpc_mem_powerdown) { if (power_on && mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU1_SHAPER_MEM_PWR_STATE, 0, 1, max_retries); REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU1_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU1_3DLUT_MEM_PWR_STATE, 0, 1, max_retries); REG_WAIT(MPC_RMU_MEM_PWR_CTRL, MPC_RMU1_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
} }
@@ -862,7 +862,7 @@ bool mpc3_program_shaper(
return false; return false;
} }
if (mpc->ctx->dc->debug.enable_mpc_mem_powerdown) if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
mpc3_power_on_shaper_3dlut(mpc, rmu_idx, true); mpc3_power_on_shaper_3dlut(mpc, rmu_idx, true);
current_mode = mpc3_get_shaper_current(mpc, rmu_idx); current_mode = mpc3_get_shaper_current(mpc, rmu_idx);
@@ -1223,7 +1223,7 @@ bool mpc3_program_3dlut(
mpc3_set_3dlut_mode(mpc, mode, is_12bits_color_channel, mpc3_set_3dlut_mode(mpc, mode, is_12bits_color_channel,
is_17x17x17, rmu_idx); is_17x17x17, rmu_idx);
if (mpc->ctx->dc->debug.enable_mpc_mem_powerdown) if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
mpc3_power_on_shaper_3dlut(mpc, rmu_idx, false); mpc3_power_on_shaper_3dlut(mpc, rmu_idx, false);
return true; return true;
@@ -1386,7 +1386,7 @@ static void mpc3_mpc_init(struct mpc *mpc)
mpc1_mpc_init(mpc); mpc1_mpc_init(mpc);
if (mpc->ctx->dc->debug.enable_mpc_mem_powerdown) { if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
if (mpc30->mpc_mask->MPC_RMU0_MEM_LOW_PWR_MODE && mpc30->mpc_mask->MPC_RMU1_MEM_LOW_PWR_MODE) { if (mpc30->mpc_mask->MPC_RMU0_MEM_LOW_PWR_MODE && mpc30->mpc_mask->MPC_RMU1_MEM_LOW_PWR_MODE) {
REG_UPDATE(MPC_RMU_MEM_PWR_CTRL, MPC_RMU0_MEM_LOW_PWR_MODE, 3); REG_UPDATE(MPC_RMU_MEM_PWR_CTRL, MPC_RMU0_MEM_LOW_PWR_MODE, 3);
REG_UPDATE(MPC_RMU_MEM_PWR_CTRL, MPC_RMU1_MEM_LOW_PWR_MODE, 3); REG_UPDATE(MPC_RMU_MEM_PWR_CTRL, MPC_RMU1_MEM_LOW_PWR_MODE, 3);