Commit d60f56b9 authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher

drm/amd/display: Update DCN35 clock table policy

[Why]
The new table doesn't have an implicit mapping between Fclk SOC voltage
and MemClk and it currently builds the table off of number of Fclk
states rather than DcfClock states.

The DML table in use is not correct for functionality or power and
does not align with our existing policies for DCN3x.

[How]
Build the table based on DcfClock with the following assumptions:

1. Raising Soc voltage is the most expensive operation, so assume that
running at max DispClock or DppClock is preferable.

2. Assume that we can run at max Fclk / MemClk at any state, but
restrict the maximum state to the very last entry in the table as the
worst case scenario.

3. Assume that Fclk always has a 2x multiplier on DcfClock unless the
table specifies something lower.
Reviewed-by: default avatarTaimur Hassan <syed.hassan@amd.com>
Acked-by: default avatarHamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent eb280189
......@@ -648,27 +648,47 @@ static unsigned int convert_wck_ratio(uint8_t wck_ratio)
return 1;
}
static inline uint32_t calc_dram_speed_mts(const MemPstateTable_t *entry)
{
return entry->UClk * convert_wck_ratio(entry->WckRatio) * 2;
}
static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk_mgr,
struct integrated_info *bios_info,
DpmClocks_t_dcn35 *clock_table)
{
struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
uint32_t max_pstate = 0, max_uclk = 0, max_fclk = 0;
uint32_t min_pstate = 0, max_dispclk = 0, max_dppclk = 0;
uint32_t max_fclk = 0, min_pstate = 0, max_dispclk = 0, max_dppclk = 0;
uint32_t max_pstate = 0, max_dram_speed_mts = 0, min_dram_speed_mts = 0;
int i;
/* Determine min/max p-state values. */
for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) {
if (is_valid_clock_value(clock_table->MemPstateTable[i].UClk) &&
clock_table->MemPstateTable[i].UClk > max_uclk) {
max_uclk = clock_table->MemPstateTable[i].UClk;
uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]);
if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts > max_dram_speed_mts) {
max_dram_speed_mts = dram_speed_mts;
max_pstate = i;
}
}
/* We expect the table to contain at least one valid Uclk entry. */
ASSERT(is_valid_clock_value(max_uclk));
min_dram_speed_mts = max_dram_speed_mts;
min_pstate = max_pstate;
for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) {
uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]);
if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts < min_dram_speed_mts) {
min_dram_speed_mts = dram_speed_mts;
min_pstate = i;
}
}
/* We expect the table to contain at least one valid P-state entry. */
ASSERT(clock_table->NumMemPstatesEnabled &&
is_valid_clock_value(max_dram_speed_mts) &&
is_valid_clock_value(min_dram_speed_mts));
/* dispclk and dppclk can be max at any voltage, same number of levels for both */
if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS &&
......@@ -678,25 +698,19 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
max_dppclk = find_max_clk_value(clock_table->DppClocks,
clock_table->NumDispClkLevelsEnabled);
} else {
/* Invalid number of entries in the table from PMFW. */
ASSERT(0);
}
if (clock_table->NumFclkLevelsEnabled <= NUM_FCLK_DPM_LEVELS)
max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq,
clock_table->NumFclkLevelsEnabled);
for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) {
uint32_t min_uclk = clock_table->MemPstateTable[0].UClk;
int j;
/* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */
ASSERT(clock_table->NumDcfClkLevelsEnabled > 0);
for (j = 1; j < clock_table->NumMemPstatesEnabled; j++) {
if (is_valid_clock_value(clock_table->MemPstateTable[j].UClk) &&
clock_table->MemPstateTable[j].UClk < min_uclk &&
clock_table->MemPstateTable[j].Voltage <= clock_table->SocVoltage[i]) {
min_uclk = clock_table->MemPstateTable[j].UClk;
min_pstate = j;
}
}
max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, clock_table->NumFclkLevelsEnabled);
for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
int j;
/* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
for (j = bw_params->clk_table.num_entries - 1; j > 0; j--)
if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i])
break;
......@@ -704,21 +718,26 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz;
bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz;
bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz;
bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
/* Now update clocks we do read */
bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemPstateTable[min_pstate].MemClk;
bw_params->clk_table.entries[i].voltage = clock_table->MemPstateTable[min_pstate].Voltage;
bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i];
bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i];
bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio(
clock_table->MemPstateTable[min_pstate].WckRatio);
bw_params->clk_table.entries[i].wck_ratio =
convert_wck_ratio(clock_table->MemPstateTable[min_pstate].WckRatio);
/* Dcfclk and Fclk are tied, but at a different ratio */
bw_params->clk_table.entries[i].fclk_mhz = min(max_fclk, 2 * clock_table->DcfClocks[i]);
}
/* Make sure to include at least one entry at highest pstate */
if (max_pstate != min_pstate || i == 0) {
if (i > MAX_NUM_DPM_LVL - 1)
i = MAX_NUM_DPM_LVL - 1;
bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemPstateTable[max_pstate].MemClk;
bw_params->clk_table.entries[i].voltage = clock_table->MemPstateTable[max_pstate].Voltage;
......@@ -734,6 +753,7 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
}
bw_params->clk_table.num_entries = i--;
/* Make sure all highest clocks are included*/
bw_params->clk_table.entries[i].socclk_mhz =
find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
bw_params->clk_table.entries[i].dispclk_mhz =
......@@ -752,6 +772,11 @@ static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
bw_params->clk_table.num_entries_per_clk.num_fclk_levels = clock_table->NumFclkLevelsEnabled;
bw_params->clk_table.num_entries_per_clk.num_memclk_levels = clock_table->NumMemPstatesEnabled;
bw_params->clk_table.num_entries_per_clk.num_socclk_levels = clock_table->NumSocClkLevelsEnabled;
/*
* Set any 0 clocks to max default setting. Not an issue for
* power since we aren't doing switching in such case anyway
*/
for (i = 0; i < bw_params->clk_table.num_entries; i++) {
if (!bw_params->clk_table.entries[i].fclk_mhz) {
bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment