summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c37
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c57
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h3
11 files changed, 130 insertions, 28 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
index 819d273f011d..c9c7baf45be3 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
@@ -738,6 +738,34 @@ static void dcn35_set_low_power_state(struct clk_mgr *clk_mgr_base)
}
}
+static void dcn35_set_idle_state(struct clk_mgr *clk_mgr_base, bool allow_idle)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ uint32_t val = dcn35_smu_read_ips_scratch(clk_mgr);
+
+ if (dc->debug.disable_ips == 0) {
+ val |= DMUB_IPS1_ALLOW_MASK;
+ val |= DMUB_IPS2_ALLOW_MASK;
+ } else if (dc->debug.disable_ips == DMUB_IPS_DISABLE_IPS1) {
+ val = val & ~DMUB_IPS1_ALLOW_MASK;
+ val = val & ~DMUB_IPS2_ALLOW_MASK;
+ } else if (dc->debug.disable_ips == DMUB_IPS_DISABLE_IPS2) {
+ val |= DMUB_IPS1_ALLOW_MASK;
+ val = val & ~DMUB_IPS2_ALLOW_MASK;
+ } else if (dc->debug.disable_ips == DMUB_IPS_DISABLE_IPS2_Z10) {
+ val |= DMUB_IPS1_ALLOW_MASK;
+ val |= DMUB_IPS2_ALLOW_MASK;
+ }
+
+ if (!allow_idle) {
+ val = val & ~DMUB_IPS1_ALLOW_MASK;
+ val = val & ~DMUB_IPS2_ALLOW_MASK;
+ }
+
+ dcn35_smu_write_ips_scratch(clk_mgr, val);
+}
+
static void dcn35_exit_low_power_state(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
@@ -757,6 +785,13 @@ static bool dcn35_is_ips_supported(struct clk_mgr *clk_mgr_base)
return ips_supported;
}
+static uint32_t dcn35_get_idle_state(struct clk_mgr *clk_mgr_base)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+ return dcn35_smu_read_ips_scratch(clk_mgr);
+}
+
static void dcn35_init_clocks_fpga(struct clk_mgr *clk_mgr)
{
dcn35_init_clocks(clk_mgr);
@@ -844,6 +879,8 @@ static struct clk_mgr_funcs dcn35_funcs = {
.set_low_power_state = dcn35_set_low_power_state,
.exit_low_power_state = dcn35_exit_low_power_state,
.is_ips_supported = dcn35_is_ips_supported,
+ .set_idle_state = dcn35_set_idle_state,
+ .get_idle_state = dcn35_get_idle_state
};
struct clk_mgr_funcs dcn35_fpga_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c
index f42c0a727dc8..cf74e69cb2a1 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c
@@ -444,9 +444,9 @@ void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *cl
enable);
}
-void dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr)
+int dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr)
{
- dcn35_smu_send_msg_with_param(
+ return dcn35_smu_send_msg_with_param(
clk_mgr,
VBIOSSMC_MSG_DispPsrExit,
0);
@@ -459,3 +459,13 @@ int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr)
VBIOSSMC_MSG_QueryIPS2Support,
0);
}
+
+void dcn35_smu_write_ips_scratch(struct clk_mgr_internal *clk_mgr, uint32_t param)
+{
+ REG_WRITE(MP1_SMN_C2PMSG_71, param);
+}
+
+uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr)
+{
+ return REG_READ(MP1_SMN_C2PMSG_71);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.h
index 4d441d6db8d0..8fb65a49351b 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.h
@@ -174,8 +174,10 @@ void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zst
void dcn35_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable);
void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable);
-void dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr);
+int dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr);
int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr);
int dcn35_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr);
int dcn35_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr);
+void dcn35_smu_write_ips_scratch(struct clk_mgr_internal *clk_mgr, uint32_t param);
+uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr);
#endif /* DAL_DC_35_SMU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index c0081d756694..c15b4d5c4e6c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -965,6 +965,8 @@ struct dc_debug_options {
bool replay_skip_crtc_disabled;
bool ignore_pg;/*do nothing, let pmfw control it*/
bool psp_disabled_wa;
+ unsigned int ips2_eval_delay_us;
+ unsigned int ips2_entry_delay_us;
};
struct gpu_info_soc_bounding_box_v1_0;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index 91b3a4610957..973d7938f47b 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1100,31 +1100,64 @@ void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
cmd.idle_opt_notify_idle.cntl_data.driver_idle = allow_idle;
- dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
+ if (allow_idle) {
+ if (dc->hwss.set_idle_state)
+ dc->hwss.set_idle_state(dc, true);
+ }
- if (allow_idle)
- udelay(500);
+ dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
{
+ uint32_t allow_state = 0;
+ uint32_t commit_state = 0;
+
if (dc->debug.dmcub_emulation)
return;
if (!dc->idle_optimizations_allowed)
return;
- // Tell PMFW to exit low power state
- if (dc->clk_mgr->funcs->exit_low_power_state)
- dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
+ if (dc->hwss.get_idle_state &&
+ dc->hwss.set_idle_state &&
+ dc->clk_mgr->funcs->exit_low_power_state) {
+
+ allow_state = dc->hwss.get_idle_state(dc);
+ dc->hwss.set_idle_state(dc, false);
+
+ if (allow_state & DMUB_IPS2_ALLOW_MASK) {
+ // Wait for evaluation time
+ udelay(dc->debug.ips2_eval_delay_us);
+ commit_state = dc->hwss.get_idle_state(dc);
+ if (commit_state & DMUB_IPS2_COMMIT_MASK) {
+ // Tell PMFW to exit low power state
+ dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
+
+ // Wait for IPS2 entry upper bound
+ udelay(dc->debug.ips2_entry_delay_us);
+ dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
- // Wait for dmcub to load up
- dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true);
+ do {
+ commit_state = dc->hwss.get_idle_state(dc);
+ } while (commit_state & DMUB_IPS2_COMMIT_MASK);
- // Notify dmcub disallow idle
- dc_dmub_srv_notify_idle(dc, false);
+ if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
+ ASSERT(0);
+
+ return;
+ }
+ }
+
+ dc_dmub_srv_notify_idle(dc, false);
+ if (allow_state & DMUB_IPS1_ALLOW_MASK) {
+ do {
+ commit_state = dc->hwss.get_idle_state(dc);
+ } while (commit_state & DMUB_IPS1_COMMIT_MASK);
+ }
+ }
- // Confirm dmu is powered up
- dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true);
+ if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true))
+ ASSERT(0);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c
index 06960fada059..03ef7820139a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c
@@ -647,18 +647,10 @@ bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)
// TODO: review other cases when idle optimization is allowed
- if (!enable) {
- // Tell PMFW to exit low power state
- if (dc->clk_mgr->funcs->exit_low_power_state)
- dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);
-
- dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true);
- }
-
- dc_dmub_srv_notify_idle(dc, enable);
-
if (!enable)
- dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true);
+ dc_dmub_srv_exit_low_power_state(dc);
+ else
+ dc_dmub_srv_notify_idle(dc, enable);
return true;
}
@@ -1192,3 +1184,19 @@ void dcn35_optimize_bandwidth(
dc->hwss.root_clock_control(dc, &pg_update_state, false);
}
}
+
+void dcn35_set_idle_state(const struct dc *dc, bool allow_idle)
+{
+ // TODO: Find a more suitable communcation
+ if (dc->clk_mgr->funcs->set_idle_state)
+ dc->clk_mgr->funcs->set_idle_state(dc->clk_mgr, allow_idle);
+}
+
+uint32_t dcn35_get_idle_state(const struct dc *dc)
+{
+ // TODO: Find a more suitable communcation
+ if (dc->clk_mgr->funcs->get_idle_state)
+ return dc->clk_mgr->funcs->get_idle_state(dc->clk_mgr);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h
index 7c0ff7b163a9..14bbdb0fa634 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h
@@ -79,4 +79,7 @@ void dcn35_dsc_pg_control(
struct dce_hwseq *hws,
unsigned int dsc_inst,
bool power_on);
+
+void dcn35_set_idle_state(const struct dc *dc, bool allow_idle);
+uint32_t dcn35_get_idle_state(const struct dc *dc);
#endif /* __DC_HWSS_DCN35_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c
index d68efe5c64a4..a9553a87b959 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c
@@ -117,7 +117,9 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.calc_blocks_to_gate = dcn35_calc_blocks_to_gate,
.calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate,
.block_power_control = dcn35_block_power_control,
- .root_clock_control = dcn35_root_clock_control
+ .root_clock_control = dcn35_root_clock_control,
+ .set_idle_state = dcn35_set_idle_state,
+ .get_idle_state = dcn35_get_idle_state
};
static const struct hwseq_private_funcs dcn35_private_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c
index 06fd02084d7c..67ff19d4116d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c
@@ -748,6 +748,8 @@ static const struct dc_debug_options debug_defaults_drv = {
.ignore_pg = true,
.psp_disabled_wa = true,
.disable_ips = true,
+ .ips2_eval_delay_us = 200,
+ .ips2_entry_delay_us = 400
};
static const struct dc_panel_config panel_config_defaults = {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
index cb2dc3f75ae2..fa9614bcb160 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
@@ -262,6 +262,8 @@ struct clk_mgr_funcs {
void (*set_low_power_state)(struct clk_mgr *clk_mgr);
void (*exit_low_power_state)(struct clk_mgr *clk_mgr);
bool (*is_ips_supported)(struct clk_mgr *clk_mgr);
+ void (*set_idle_state)(struct clk_mgr *clk_mgr, bool allow_idle);
+ uint32_t (*get_idle_state)(struct clk_mgr *clk_mgr);
void (*init_clocks)(struct clk_mgr *clk_mgr);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
index e0dd56182841..d4d59a916668 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -422,7 +422,8 @@ struct hw_sequencer_funcs {
struct pg_block_update *update_state, bool power_on);
void (*root_clock_control)(struct dc *dc,
struct pg_block_update *update_state, bool power_on);
-
+ void (*set_idle_state)(const struct dc *dc, bool allow_idle);
+ uint32_t (*get_idle_state)(const struct dc *dc);
void (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context);
void (*subvp_pipe_control_lock)(struct dc *dc,