From cae78e0331459643e21b982e4833a6525a43e498 Mon Sep 17 00:00:00 2001 From: Jacky Liao Date: Thu, 15 Oct 2020 17:42:16 -0400 Subject: [PATCH] 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 Reviewed-by: Eric Yang Acked-by: Qingqing Zhuo Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 10 +++++++++- drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h | 12 ++++++++++-- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c | 6 ++++++ drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c | 14 +++++++------- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 273963e..87bc102 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -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 { enum visual_confirm visual_confirm; bool sanity_checks; @@ -506,7 +514,7 @@ struct dc_debug_options { bool disable_dsc; bool enable_dram_clock_change_one_display_vactive; 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 { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index b77e22b..a8103c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -607,6 +607,10 @@ struct dce_hwseq_registers { uint32_t MC_VM_XGMI_LFB_CNTL; uint32_t AZALIA_AUDIO_DTO; 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 */ #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) #define HWSEQ_DCN30_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 #if defined(CONFIG_DRM_AMD_DC_DCN3_01) @@ -1059,7 +1065,9 @@ struct dce_hwseq_registers { type D2VGA_MODE_ENABLE; \ type D3VGA_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) #define HWSEQ_DCN3_REG_FIELD_LIST(type) \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index 7195257..b07ccc8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -462,6 +462,12 @@ void dcn30_init_hw(struct dc *dc) 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) { res_pool->ref_clocks.xtalin_clock_inKhz = dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c index 1671688..d7d053f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.c @@ -143,7 +143,7 @@ static void mpc3_power_on_ogam_lut( { 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 REG_UPDATE(MPCC_MEM_PWR_CTRL[mpcc_id], MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0); // Wait for confirmation when powering on @@ -369,7 +369,7 @@ void mpc3_set_output_gamma( REG_UPDATE(MPCC_OGAM_CONTROL[mpcc_id], 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); } @@ -818,7 +818,7 @@ static void mpc3_power_on_shaper_3dlut( REG_SET(MPC_RMU_MEM_PWR_CTRL, 0, MPC_RMU0_MEM_PWR_DIS, power_on == true ? 1:0); /* 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_3DLUT_MEM_PWR_STATE, 0, 1, max_retries); } @@ -829,7 +829,7 @@ static void mpc3_power_on_shaper_3dlut( } else if (rmu_idx == 1) { REG_SET(MPC_RMU_MEM_PWR_CTRL, 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_3DLUT_MEM_PWR_STATE, 0, 1, max_retries); } @@ -862,7 +862,7 @@ bool mpc3_program_shaper( 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); 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, 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); return true; @@ -1386,7 +1386,7 @@ static void mpc3_mpc_init(struct mpc *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) { 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); -- 2.7.4