mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-20 07:41:24 -04:00
drm/amd/display: Use per pipe P-State force for FPO
[Description] * Pass in pipe index for FPO cmd to DMCUB - This change will pass in the pipe index for each stream that is using FPO - This change is in preparation to enable FPO + VActive * Use per pipe P-State force for FPO - For FPO, instead of using max watermarks value for P-State disallow, use per pipe p-state force instead - This is in preparation to enable FPO + VActive Reviewed-by: Jun Lei <Jun.Lei@amd.com> Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com> Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -302,27 +302,31 @@ static uint8_t dc_dmub_srv_get_pipes_for_stream(struct dc *dc, struct dc_stream_
|
||||
return pipes;
|
||||
}
|
||||
|
||||
static int dc_dmub_srv_get_timing_generator_offset(struct dc *dc, struct dc_stream_state *stream)
|
||||
static void dc_dmub_srv_populate_fams_pipe_info(struct dc *dc, struct dc_state *context,
|
||||
struct pipe_ctx *head_pipe,
|
||||
struct dmub_cmd_fw_assisted_mclk_switch_pipe_data *fams_pipe_data)
|
||||
{
|
||||
int tg_inst = 0;
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
|
||||
// TODO: Uncomment once FW headers are updated in driver
|
||||
//fams_pipe_data->pipe_index[pipe_idx++] = head_pipe->plane_res.hubp->inst;
|
||||
for (j = 0; j < dc->res_pool->pipe_count; j++) {
|
||||
struct pipe_ctx *split_pipe = &context->res_ctx.pipe_ctx[j];
|
||||
|
||||
if (pipe->stream == stream && pipe->stream_res.tg) {
|
||||
tg_inst = pipe->stream_res.tg->inst;
|
||||
break;
|
||||
if (split_pipe->stream == head_pipe->stream && (split_pipe->top_pipe || split_pipe->prev_odm_pipe)) {
|
||||
// TODO: Uncomment once FW headers are updated in driver
|
||||
//fams_pipe_data->pipe_index[pipe_idx++] = split_pipe->plane_res.hubp->inst;
|
||||
}
|
||||
}
|
||||
return tg_inst;
|
||||
// TODO: Uncomment once FW headers are updated in driver
|
||||
//fams_pipe_data->pipe_count = pipe_idx;
|
||||
}
|
||||
|
||||
bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, struct dc_state *context)
|
||||
{
|
||||
union dmub_rb_cmd cmd = { 0 };
|
||||
struct dmub_cmd_fw_assisted_mclk_switch_config *config_data = &cmd.fw_assisted_mclk_switch.config_data;
|
||||
int i = 0;
|
||||
int i = 0, k = 0;
|
||||
int ramp_up_num_steps = 1; // TODO: Ramp is currently disabled. Reenable it.
|
||||
uint8_t visual_confirm_enabled;
|
||||
|
||||
@@ -337,17 +341,21 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru
|
||||
cmd.fw_assisted_mclk_switch.config_data.fams_enabled = should_manage_pstate;
|
||||
cmd.fw_assisted_mclk_switch.config_data.visual_confirm_enabled = visual_confirm_enabled;
|
||||
|
||||
for (i = 0; context && i < context->stream_count; i++) {
|
||||
struct dc_stream_state *stream = context->streams[i];
|
||||
uint8_t min_refresh_in_hz = (stream->timing.min_refresh_in_uhz + 999999) / 1000000;
|
||||
int tg_inst = dc_dmub_srv_get_timing_generator_offset(dc, stream);
|
||||
for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
config_data->pipe_data[tg_inst].pix_clk_100hz = stream->timing.pix_clk_100hz;
|
||||
config_data->pipe_data[tg_inst].min_refresh_in_hz = min_refresh_in_hz;
|
||||
config_data->pipe_data[tg_inst].max_ramp_step = ramp_up_num_steps;
|
||||
config_data->pipe_data[tg_inst].pipes = dc_dmub_srv_get_pipes_for_stream(dc, stream);
|
||||
if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->fpo_in_use) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
uint8_t min_refresh_in_hz = (pipe->stream->timing.min_refresh_in_uhz + 999999) / 1000000;
|
||||
|
||||
config_data->pipe_data[k].pix_clk_100hz = pipe->stream->timing.pix_clk_100hz;
|
||||
config_data->pipe_data[k].min_refresh_in_hz = min_refresh_in_hz;
|
||||
config_data->pipe_data[k].max_ramp_step = ramp_up_num_steps;
|
||||
config_data->pipe_data[k].pipes = dc_dmub_srv_get_pipes_for_stream(dc, pipe->stream);
|
||||
dc_dmub_srv_populate_fams_pipe_info(dc, context, pipe, &config_data->pipe_data[k]);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
cmd.fw_assisted_mclk_switch.header.payload_bytes =
|
||||
sizeof(cmd.fw_assisted_mclk_switch) - sizeof(cmd.fw_assisted_mclk_switch.header);
|
||||
|
||||
|
||||
@@ -293,6 +293,7 @@ struct dc_stream_state {
|
||||
|
||||
bool has_non_synchronizable_pclk;
|
||||
bool vblank_synchronized;
|
||||
bool fpo_in_use;
|
||||
struct mall_stream_config mall_stream_config;
|
||||
};
|
||||
|
||||
|
||||
@@ -1993,6 +1993,16 @@ void dcn20_post_unlock_program_front_end(
|
||||
}
|
||||
}
|
||||
|
||||
/* P-State support transitions:
|
||||
* Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe
|
||||
* FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally)
|
||||
* Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe
|
||||
* FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe
|
||||
* FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes
|
||||
*/
|
||||
if (hwseq && hwseq->funcs.update_force_pstate)
|
||||
dc->hwseq->funcs.update_force_pstate(dc, context);
|
||||
|
||||
/* Only program the MALL registers after all the main and phantom pipes
|
||||
* are done programming.
|
||||
*/
|
||||
|
||||
@@ -2016,6 +2016,8 @@ bool dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc,
|
||||
if (context->streams[0]->vrr_active_variable)
|
||||
return false;
|
||||
|
||||
context->streams[0]->fpo_in_use = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,15 @@ void hubp32_update_force_pstate_disallow(struct hubp *hubp, bool pstate_disallow
|
||||
DATA_UCLK_PSTATE_FORCE_VALUE, 0);
|
||||
}
|
||||
|
||||
void hubp32_update_force_cursor_pstate_disallow(struct hubp *hubp, bool pstate_disallow)
|
||||
{
|
||||
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
|
||||
|
||||
REG_UPDATE_2(UCLK_PSTATE_FORCE,
|
||||
CURSOR_UCLK_PSTATE_FORCE_EN, pstate_disallow,
|
||||
CURSOR_UCLK_PSTATE_FORCE_VALUE, 0);
|
||||
}
|
||||
|
||||
void hubp32_update_mall_sel(struct hubp *hubp, uint32_t mall_sel, bool c_cursor)
|
||||
{
|
||||
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
|
||||
@@ -188,6 +197,7 @@ static struct hubp_funcs dcn32_hubp_funcs = {
|
||||
.hubp_set_flip_int = hubp1_set_flip_int,
|
||||
.hubp_in_blank = hubp1_in_blank,
|
||||
.hubp_update_force_pstate_disallow = hubp32_update_force_pstate_disallow,
|
||||
.hubp_update_force_cursor_pstate_disallow = hubp32_update_force_cursor_pstate_disallow,
|
||||
.phantom_hubp_post_enable = hubp32_phantom_hubp_post_enable,
|
||||
.hubp_update_mall_sel = hubp32_update_mall_sel,
|
||||
.hubp_prepare_subvp_buffering = hubp32_prepare_subvp_buffering
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
void hubp32_update_force_pstate_disallow(struct hubp *hubp, bool pstate_disallow);
|
||||
|
||||
void hubp32_update_force_cursor_pstate_disallow(struct hubp *hubp, bool pstate_disallow);
|
||||
|
||||
void hubp32_update_mall_sel(struct hubp *hubp, uint32_t mall_sel, bool c_cursor);
|
||||
|
||||
void hubp32_prepare_subvp_buffering(struct hubp *hubp, bool enable);
|
||||
|
||||
@@ -571,40 +571,51 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Program P-State force value according to if pipe is using SubVP or not:
|
||||
/* Program P-State force value according to if pipe is using SubVP / FPO or not:
|
||||
* 1. Reset P-State force on all pipes first
|
||||
* 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB)
|
||||
*/
|
||||
void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context)
|
||||
void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context)
|
||||
{
|
||||
int i;
|
||||
int num_subvp = 0;
|
||||
/* Unforce p-state for each pipe
|
||||
|
||||
/* Unforce p-state for each pipe if it is not FPO or SubVP.
|
||||
* For FPO and SubVP, if it's already forced disallow, leave
|
||||
* it as disallow.
|
||||
*/
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
struct hubp *hubp = pipe->plane_res.hubp;
|
||||
|
||||
if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
|
||||
hubp->funcs->hubp_update_force_pstate_disallow(hubp, false);
|
||||
if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN)
|
||||
num_subvp++;
|
||||
if (!pipe->stream || (pipe->stream && !(pipe->stream->mall_stream_config.type == SUBVP_MAIN ||
|
||||
pipe->stream->fpo_in_use))) {
|
||||
if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
|
||||
hubp->funcs->hubp_update_force_pstate_disallow(hubp, false);
|
||||
if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow)
|
||||
hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_subvp == 0)
|
||||
return;
|
||||
|
||||
/* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false.
|
||||
*/
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
struct hubp *hubp = pipe->plane_res.hubp;
|
||||
|
||||
if (pipe->stream && pipe->plane_state && (pipe->stream->mall_stream_config.type == SUBVP_MAIN)) {
|
||||
struct hubp *hubp = pipe->plane_res.hubp;
|
||||
|
||||
if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
|
||||
if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
|
||||
hubp->funcs->hubp_update_force_pstate_disallow(hubp, true);
|
||||
}
|
||||
|
||||
if (pipe->stream && pipe->stream->fpo_in_use) {
|
||||
if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
|
||||
hubp->funcs->hubp_update_force_pstate_disallow(hubp, true);
|
||||
/* For now only force cursor p-state disallow for FPO
|
||||
* Needs to be added for subvp once FW side gets updated
|
||||
*/
|
||||
if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow)
|
||||
hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,10 +688,6 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context)
|
||||
if (hws && hws->funcs.update_mall_sel)
|
||||
hws->funcs.update_mall_sel(dc, context);
|
||||
|
||||
//update subvp force pstate
|
||||
if (hws && hws->funcs.subvp_update_force_pstate)
|
||||
dc->hwseq->funcs.subvp_update_force_pstate(dc, context);
|
||||
|
||||
// Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
@@ -67,7 +67,7 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context);
|
||||
|
||||
void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context);
|
||||
|
||||
void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context);
|
||||
void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context);
|
||||
|
||||
void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx);
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ static const struct hwseq_private_funcs dcn32_private_funcs = {
|
||||
.dccg_init = dcn20_dccg_init,
|
||||
.set_mcm_luts = dcn32_set_mcm_luts,
|
||||
.program_mall_pipe_config = dcn32_program_mall_pipe_config,
|
||||
.subvp_update_force_pstate = dcn32_subvp_update_force_pstate,
|
||||
.update_force_pstate = dcn32_update_force_pstate,
|
||||
.update_mall_sel = dcn32_update_mall_sel,
|
||||
.calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
|
||||
.set_pixels_per_cycle = dcn32_set_pixels_per_cycle,
|
||||
|
||||
@@ -389,6 +389,10 @@ void dcn30_fpu_calculate_wm_and_dlg(
|
||||
dc_assert_fp_enabled();
|
||||
|
||||
context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
|
||||
for (i = 0; i < context->stream_count; i++) {
|
||||
if (context->streams[i])
|
||||
context->streams[i]->fpo_in_use = false;
|
||||
}
|
||||
|
||||
if (!pstate_en) {
|
||||
/* only when the mclk switch can not be natural, is the fw based vblank stretch attempted */
|
||||
|
||||
@@ -1960,6 +1960,10 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
|
||||
}
|
||||
|
||||
context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false;
|
||||
for (i = 0; i < context->stream_count; i++) {
|
||||
if (context->streams[i])
|
||||
context->streams[i]->fpo_in_use = false;
|
||||
}
|
||||
|
||||
if (!pstate_en || (!dc->debug.disable_fpo_optimizations &&
|
||||
pstate_en && vlevel != 0)) {
|
||||
@@ -2199,10 +2203,6 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
|
||||
context->bw_ctx.dml.soc.dram_clock_change_latency_us =
|
||||
dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
|
||||
|
||||
if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {
|
||||
dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(dc, context);
|
||||
}
|
||||
|
||||
/* revert fclk lat changes if required */
|
||||
if (need_fclk_lat_as_dummy)
|
||||
context->bw_ctx.dml.soc.fclk_change_latency_us =
|
||||
|
||||
@@ -203,6 +203,7 @@ struct hubp_funcs {
|
||||
void (*hubp_soft_reset)(struct hubp *hubp, bool reset);
|
||||
|
||||
void (*hubp_update_force_pstate_disallow)(struct hubp *hubp, bool allow);
|
||||
void (*hubp_update_force_cursor_pstate_disallow)(struct hubp *hubp, bool allow);
|
||||
void (*hubp_update_mall_sel)(struct hubp *hubp, uint32_t mall_sel, bool c_cursor);
|
||||
void (*hubp_prepare_subvp_buffering)(struct hubp *hubp, bool enable);
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ struct hwseq_private_funcs {
|
||||
void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable);
|
||||
#ifdef CONFIG_DRM_AMD_DC_FP
|
||||
void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context);
|
||||
void (*subvp_update_force_pstate)(struct dc *dc, struct dc_state *context);
|
||||
void (*update_force_pstate)(struct dc *dc, struct dc_state *context);
|
||||
void (*update_mall_sel)(struct dc *dc, struct dc_state *context);
|
||||
unsigned int (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx,
|
||||
unsigned int *k1_div,
|
||||
|
||||
Reference in New Issue
Block a user