From f2459c52c84449c0494365f928d1a0cbe52f23cf Mon Sep 17 00:00:00 2001 From: Sung Lee Date: Tue, 25 Aug 2020 15:52:17 -0400 Subject: drm/amd/display: Add Bounding Box State for Low DF PState but High Voltage State [WHY] DF PState and Voltage State are coupled such that one cannot be raised without raising the other. This uses more power than is necessary in high bandwidth scenarios. [HOW] Add logic to create a new bounding box state that allows for DF PState to be low while Voltage State is high. Watermarks vlevel calculation logic was also udpated to assume state 1 contains the new optimized state. Signed-off-by: Sung Lee Acked-by: Aurabindo Pillai Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn21/dcn21_resource.c | 71 ++++++++++++++++------ 1 file changed, 53 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c') diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index 686e1d47faa4..72cbc13ce3da 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -1154,12 +1154,12 @@ void dcn21_calculate_wm( &context->bw_ctx.dml, pipes, pipe_cnt); /* WM Set C */ table_entry = &bw_params->wm_table.entries[WM_C]; - vlevel = MIN(MAX(vlevel_req, 2), vlevel_max); + vlevel = MIN(MAX(vlevel_req, 3), vlevel_max); calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, &context->bw_ctx.dml, pipes, pipe_cnt); /* WM Set B */ table_entry = &bw_params->wm_table.entries[WM_B]; - vlevel = MIN(MAX(vlevel_req, 1), vlevel_max); + vlevel = MIN(MAX(vlevel_req, 2), vlevel_max); calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, &context->bw_ctx.dml, pipes, pipe_cnt); @@ -1385,12 +1385,39 @@ struct display_stream_compressor *dcn21_dsc_create( return &dsc->base; } +static struct _vcs_dpi_voltage_scaling_st construct_low_pstate_lvl(struct clk_limit_table *clk_table, unsigned int high_voltage_lvl) +{ + struct _vcs_dpi_voltage_scaling_st low_pstate_lvl; + int i; + + low_pstate_lvl.state = 1; + low_pstate_lvl.dcfclk_mhz = clk_table->entries[0].dcfclk_mhz; + low_pstate_lvl.fabricclk_mhz = clk_table->entries[0].fclk_mhz; + low_pstate_lvl.socclk_mhz = clk_table->entries[0].socclk_mhz; + low_pstate_lvl.dram_speed_mts = clk_table->entries[0].memclk_mhz * 2; + + low_pstate_lvl.dispclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dispclk_mhz; + low_pstate_lvl.dppclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dppclk_mhz; + low_pstate_lvl.dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[high_voltage_lvl].dram_bw_per_chan_gbps; + low_pstate_lvl.dscclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dscclk_mhz; + low_pstate_lvl.dtbclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dtbclk_mhz; + low_pstate_lvl.phyclk_d18_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_d18_mhz; + low_pstate_lvl.phyclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_mhz; + + for (i = clk_table->num_entries; i > 1; i--) + clk_table->entries[i] = clk_table->entries[i-1]; + clk_table->entries[1] = clk_table->entries[0]; + clk_table->num_entries++; + + return low_pstate_lvl; +} + static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) { struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool); struct clk_limit_table *clk_table = &bw_params->clk_table; struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES]; - unsigned int i, closest_clk_lvl; + unsigned int i, closest_clk_lvl = 0, k = 0; int j; dcn2_1_ip.max_num_otg = pool->base.res_cap->num_timing_generator; @@ -1407,27 +1434,35 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param } } - clock_limits[i].state = i; - clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; - clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; - clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; - clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; - - clock_limits[i].dispclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz; - clock_limits[i].dppclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz; - clock_limits[i].dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; - clock_limits[i].dscclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz; - clock_limits[i].dtbclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; - clock_limits[i].phyclk_d18_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; - clock_limits[i].phyclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz; + /* clk_table[1] is reserved for min DF PState. skip here to fill in later. */ + if (i == 1) + k++; + + clock_limits[k].state = k; + clock_limits[k].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; + clock_limits[k].fabricclk_mhz = clk_table->entries[i].fclk_mhz; + clock_limits[k].socclk_mhz = clk_table->entries[i].socclk_mhz; + clock_limits[k].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2; + + clock_limits[k].dispclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz; + clock_limits[k].dppclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz; + clock_limits[k].dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps; + clock_limits[k].dscclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz; + clock_limits[k].dtbclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz; + clock_limits[k].phyclk_d18_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz; + clock_limits[k].phyclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz; + + k++; } - for (i = 0; i < clk_table->num_entries; i++) + for (i = 0; i < clk_table->num_entries + 1; i++) dcn2_1_soc.clock_limits[i] = clock_limits[i]; if (clk_table->num_entries) { - dcn2_1_soc.num_states = clk_table->num_entries; + dcn2_1_soc.num_states = clk_table->num_entries + 1; /* duplicate last level */ dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1]; dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states; + /* fill in min DF PState */ + dcn2_1_soc.clock_limits[1] = construct_low_pstate_lvl(clk_table, closest_clk_lvl); } dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21); -- cgit v1.2.3