Skip to content

Commit 4866b0b

Browse files
leungmartinalexdeucher
authored andcommitted
drm/amd/display: implement dc_mode_memclk
why: Need interface to lower clocks when in dc (power save) mode. Must be able to work with p_state unsupported cases Can cause flicker when OS notifies us of dc state change how: added dal3 interface for KMD added pathway to query smu for this softmax added blank before clock change to override underflow added logic to change clk based on pstatesupport and softmax added logic in prepare/optimize_bw to conform while changing clocks Reviewed-by: Aric Cyr <[email protected]> Acked-by: Pavle Kotarac <[email protected]> Tested-by: Daniel Wheeler <[email protected]> Signed-off-by: Martin Leung <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent b477143 commit 4866b0b

File tree

14 files changed

+188
-7
lines changed

14 files changed

+188
-7
lines changed

drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base,
252252
bool update_dispclk = false;
253253
bool enter_display_off = false;
254254
bool dpp_clock_lowered = false;
255+
bool update_pstate_unsupported_clk = false;
255256
struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
256257
bool force_reset = false;
257258
bool update_uclk = false;
@@ -299,13 +300,28 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base,
299300
clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support;
300301
total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context);
301302
p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0);
302-
if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
303+
304+
// invalidate the current P-State forced min in certain dc_mode_softmax situations
305+
if (dc->clk_mgr->dc_mode_softmax_enabled && safe_to_lower && !p_state_change_support) {
306+
if ((new_clocks->dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) !=
307+
(clk_mgr_base->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000))
308+
update_pstate_unsupported_clk = true;
309+
}
310+
311+
if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support) ||
312+
update_pstate_unsupported_clk) {
303313
clk_mgr_base->clks.p_state_change_support = p_state_change_support;
304314

305315
/* to disable P-State switching, set UCLK min = max */
306-
if (!clk_mgr_base->clks.p_state_change_support)
307-
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
316+
if (!clk_mgr_base->clks.p_state_change_support) {
317+
if (dc->clk_mgr->dc_mode_softmax_enabled &&
318+
new_clocks->dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
319+
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
320+
dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
321+
else
322+
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
308323
clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
324+
}
309325
}
310326

311327
/* Always update saved value, even if new value not set due to P-State switching unsupported */
@@ -421,6 +437,24 @@ static void dcn3_set_hard_max_memclk(struct clk_mgr *clk_mgr_base)
421437
clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
422438
}
423439

440+
static void dcn3_set_max_memclk(struct clk_mgr *clk_mgr_base, unsigned int memclk_mhz)
441+
{
442+
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
443+
444+
if (!clk_mgr->smu_present)
445+
return;
446+
447+
dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, memclk_mhz);
448+
}
449+
static void dcn3_set_min_memclk(struct clk_mgr *clk_mgr_base, unsigned int memclk_mhz)
450+
{
451+
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
452+
453+
if (!clk_mgr->smu_present)
454+
return;
455+
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, memclk_mhz);
456+
}
457+
424458
/* Get current memclk states, update bounding box */
425459
static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
426460
{
@@ -436,6 +470,8 @@ static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
436470
&num_levels);
437471
clk_mgr_base->bw_params->clk_table.num_entries = num_levels ? num_levels : 1;
438472

473+
clk_mgr_base->bw_params->dc_mode_softmax_memclk = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
474+
439475
/* Refresh bounding box */
440476
clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
441477
clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
@@ -505,6 +541,8 @@ static struct clk_mgr_funcs dcn3_funcs = {
505541
.notify_wm_ranges = dcn3_notify_wm_ranges,
506542
.set_hard_min_memclk = dcn3_set_hard_min_memclk,
507543
.set_hard_max_memclk = dcn3_set_hard_max_memclk,
544+
.set_max_memclk = dcn3_set_max_memclk,
545+
.set_min_memclk = dcn3_set_min_memclk,
508546
.get_memclk_states_from_smu = dcn3_get_memclk_states_from_smu,
509547
.are_clock_states_equal = dcn3_are_clock_states_equal,
510548
.enable_pme_wa = dcn3_enable_pme_wa,

drivers/gpu/drm/amd/display/dc/core/dc.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3605,6 +3605,98 @@ void dc_lock_memory_clock_frequency(struct dc *dc)
36053605
core_link_enable_stream(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
36063606
}
36073607

3608+
static void blank_and_force_memclk(struct dc *dc, bool apply, unsigned int memclk_mhz)
3609+
{
3610+
struct dc_state *context = dc->current_state;
3611+
struct hubp *hubp;
3612+
struct pipe_ctx *pipe;
3613+
int i;
3614+
3615+
for (i = 0; i < dc->res_pool->pipe_count; i++) {
3616+
pipe = &context->res_ctx.pipe_ctx[i];
3617+
3618+
if (pipe->stream != NULL) {
3619+
dc->hwss.disable_pixel_data(dc, pipe, true);
3620+
3621+
// wait for double buffer
3622+
pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VACTIVE);
3623+
pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK);
3624+
pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VACTIVE);
3625+
3626+
hubp = pipe->plane_res.hubp;
3627+
hubp->funcs->set_blank_regs(hubp, true);
3628+
}
3629+
}
3630+
3631+
dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, memclk_mhz);
3632+
dc->clk_mgr->funcs->set_min_memclk(dc->clk_mgr, memclk_mhz);
3633+
3634+
for (i = 0; i < dc->res_pool->pipe_count; i++) {
3635+
pipe = &context->res_ctx.pipe_ctx[i];
3636+
3637+
if (pipe->stream != NULL) {
3638+
dc->hwss.disable_pixel_data(dc, pipe, false);
3639+
3640+
hubp = pipe->plane_res.hubp;
3641+
hubp->funcs->set_blank_regs(hubp, false);
3642+
}
3643+
}
3644+
}
3645+
3646+
3647+
/**
3648+
* dc_enable_dcmode_clk_limit() - lower clocks in dc (battery) mode
3649+
* @dc: pointer to dc of the dm calling this
3650+
* @enable: True = transition to DC mode, false = transition back to AC mode
3651+
*
3652+
* Some SoCs define additional clock limits when in DC mode, DM should
3653+
* invoke this function when the platform undergoes a power source transition
3654+
* so DC can apply/unapply the limit. This interface may be disruptive to
3655+
* the onscreen content.
3656+
*
3657+
* Context: Triggered by OS through DM interface, or manually by escape calls.
3658+
* Need to hold a dclock when doing so.
3659+
*
3660+
* Return: none (void function)
3661+
*
3662+
*/
3663+
void dc_enable_dcmode_clk_limit(struct dc *dc, bool enable)
3664+
{
3665+
uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev;
3666+
unsigned int softMax, maxDPM, funcMin;
3667+
bool p_state_change_support;
3668+
3669+
if (!ASICREV_IS_BEIGE_GOBY_P(hw_internal_rev))
3670+
return;
3671+
3672+
softMax = dc->clk_mgr->bw_params->dc_mode_softmax_memclk;
3673+
maxDPM = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz;
3674+
funcMin = (dc->clk_mgr->clks.dramclk_khz + 999) / 1000;
3675+
p_state_change_support = dc->clk_mgr->clks.p_state_change_support;
3676+
3677+
if (enable && !dc->clk_mgr->dc_mode_softmax_enabled) {
3678+
if (p_state_change_support) {
3679+
if (funcMin <= softMax)
3680+
dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, softMax);
3681+
// else: No-Op
3682+
} else {
3683+
if (funcMin <= softMax)
3684+
blank_and_force_memclk(dc, true, softMax);
3685+
// else: No-Op
3686+
}
3687+
} else if (!enable && dc->clk_mgr->dc_mode_softmax_enabled) {
3688+
if (p_state_change_support) {
3689+
if (funcMin <= softMax)
3690+
dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, maxDPM);
3691+
// else: No-Op
3692+
} else {
3693+
if (funcMin <= softMax)
3694+
blank_and_force_memclk(dc, true, maxDPM);
3695+
// else: No-Op
3696+
}
3697+
}
3698+
dc->clk_mgr->dc_mode_softmax_enabled = enable;
3699+
}
36083700
bool dc_is_plane_eligible_for_idle_optimizations(struct dc *dc, struct dc_plane_state *plane,
36093701
struct dc_cursor_attributes *cursor_attr)
36103702
{

drivers/gpu/drm/amd/display/dc/dc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,9 @@ void dc_unlock_memory_clock_frequency(struct dc *dc);
14321432
*/
14331433
void dc_lock_memory_clock_frequency(struct dc *dc);
14341434

1435+
/* set soft max for memclk, to be used for AC/DC switching clock limitations */
1436+
void dc_enable_dcmode_clk_limit(struct dc *dc, bool enable);
1437+
14351438
/* cleanup on driver unload */
14361439
void dc_hardware_release(struct dc *dc);
14371440

drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,16 @@ bool hubp2_is_flip_pending(struct hubp *hubp)
928928
}
929929

930930
void hubp2_set_blank(struct hubp *hubp, bool blank)
931+
{
932+
hubp2_set_blank_regs(hubp, blank);
933+
934+
if (blank) {
935+
hubp->mpcc_id = 0xf;
936+
hubp->opp_id = OPP_ID_INVALID;
937+
}
938+
}
939+
940+
void hubp2_set_blank_regs(struct hubp *hubp, bool blank)
931941
{
932942
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
933943
uint32_t blank_en = blank ? 1 : 0;
@@ -950,9 +960,6 @@ void hubp2_set_blank(struct hubp *hubp, bool blank)
950960
HUBP_NO_OUTSTANDING_REQ, 1,
951961
1, 200);
952962
}
953-
954-
hubp->mpcc_id = 0xf;
955-
hubp->opp_id = OPP_ID_INVALID;
956963
}
957964
}
958965

@@ -1602,6 +1609,7 @@ static struct hubp_funcs dcn20_hubp_funcs = {
16021609
.hubp_setup_interdependent = hubp2_setup_interdependent,
16031610
.hubp_set_vm_system_aperture_settings = hubp2_set_vm_system_aperture_settings,
16041611
.set_blank = hubp2_set_blank,
1612+
.set_blank_regs = hubp2_set_blank_regs,
16051613
.dcc_control = hubp2_dcc_control,
16061614
.mem_program_viewport = min_set_viewport,
16071615
.set_cursor_attributes = hubp2_cursor_set_attributes,

drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ void hubp2_program_surface_config(
330330
bool hubp2_is_flip_pending(struct hubp *hubp);
331331

332332
void hubp2_set_blank(struct hubp *hubp, bool blank);
333+
void hubp2_set_blank_regs(struct hubp *hubp, bool blank);
333334

334335
void hubp2_cursor_set_position(
335336
struct hubp *hubp,

drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,11 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
615615
pipe_ctx->pipe_idx);
616616
}
617617

618+
void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank)
619+
{
620+
dcn20_blank_pixel_data(dc, pipe_ctx, blank);
621+
}
622+
618623
static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
619624
int opp_cnt)
620625
{
@@ -1840,6 +1845,11 @@ void dcn20_optimize_bandwidth(
18401845
dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
18411846
true);
18421847

1848+
if (dc->clk_mgr->dc_mode_softmax_enabled)
1849+
if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
1850+
context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
1851+
dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
1852+
18431853
dc->clk_mgr->funcs->update_clocks(
18441854
dc->clk_mgr,
18451855
context,

drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx);
5353
void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
5454
struct dc_link_settings *link_settings);
5555
void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx);
56+
void dcn20_disable_pixel_data(
57+
struct dc *dc,
58+
struct pipe_ctx *pipe_ctx,
59+
bool blank);
5660
void dcn20_blank_pixel_data(
5761
struct dc *dc,
5862
struct pipe_ctx *pipe_ctx,

drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ static struct hubp_funcs dcn30_hubp_funcs = {
490490
.hubp_setup_interdependent = hubp2_setup_interdependent,
491491
.hubp_set_vm_system_aperture_settings = hubp3_set_vm_system_aperture_settings,
492492
.set_blank = hubp2_set_blank,
493+
.set_blank_regs = hubp2_set_blank_regs,
493494
.dcc_control = hubp3_dcc_control,
494495
.mem_program_viewport = min_set_viewport,
495496
.set_cursor_attributes = hubp2_cursor_set_attributes,

drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,17 @@ void dcn30_enable_writeback(
344344
dwb->funcs->enable(dwb, &wb_info->dwb_params);
345345
}
346346

347+
void dcn30_prepare_bandwidth(struct dc *dc,
348+
struct dc_state *context)
349+
{
350+
if (dc->clk_mgr->dc_mode_softmax_enabled)
351+
if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
352+
context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
353+
dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
354+
355+
dcn20_prepare_bandwidth(dc, context);
356+
}
357+
347358
void dcn30_disable_writeback(
348359
struct dc *dc,
349360
unsigned int dwb_pipe_inst)

drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#define __DC_HWSS_DCN30_H__
2828

2929
#include "hw_sequencer_private.h"
30-
30+
#include "dcn20/dcn20_hwseq.h"
3131
struct dc;
3232

3333
void dcn30_init_hw(struct dc *dc);
@@ -47,6 +47,9 @@ void dcn30_disable_writeback(
4747
struct dc *dc,
4848
unsigned int dwb_pipe_inst);
4949

50+
void dcn30_prepare_bandwidth(struct dc *dc,
51+
struct dc_state *context);
52+
5053
bool dcn30_mmhubbub_warmup(
5154
struct dc *dc,
5255
unsigned int num_dwb,

0 commit comments

Comments
 (0)