mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
drm/amd/display: init dispclk from bootup clock for DCN315
[Why] Driver does not pick up and save vbios's clocks during init clocks, the dispclk in clk_mgr will keep 0. OS might change the timing (lower the pixel clock) after boot. Then driver will set the dispclk to lower when safe_to_lower is false, for in clk_mgr dispclk is zero, it's illegal and causes garbage. [How] Dump and save the vbios's clocks, and init the dispclk in dcn315_init_clocks. Reviewed-by: Charlene Liu <charlene.liu@amd.com> Signed-off-by: Zhongwei Zhang <Zhongwei.Zhang@amd.com> Signed-off-by: Wayne Lin <wayne.lin@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
9ec11bb842
commit
14bb17cc37
|
|
@ -40,7 +40,7 @@
|
|||
#include "dm_helpers.h"
|
||||
|
||||
#include "dc_dmub_srv.h"
|
||||
|
||||
#include "reg_helper.h"
|
||||
#include "logger_types.h"
|
||||
#undef DC_LOGGER
|
||||
#define DC_LOGGER \
|
||||
|
|
@ -48,9 +48,43 @@
|
|||
|
||||
#include "link_service.h"
|
||||
|
||||
#define MAX_INSTANCE 7
|
||||
#define MAX_SEGMENT 8
|
||||
|
||||
struct IP_BASE_INSTANCE {
|
||||
unsigned int segment[MAX_SEGMENT];
|
||||
};
|
||||
|
||||
struct IP_BASE {
|
||||
struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
|
||||
};
|
||||
|
||||
static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x02401800, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0x00016E00, 0x02401C00, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0x00017000, 0x02402000, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0x00017200, 0x02402400, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0x0001B000, 0x0242D800, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0x0001B200, 0x0242DC00, 0, 0, 0, 0, 0, 0 } } } };
|
||||
|
||||
#define regCLK1_CLK0_CURRENT_CNT 0x0314
|
||||
#define regCLK1_CLK0_CURRENT_CNT_BASE_IDX 0
|
||||
#define regCLK1_CLK1_CURRENT_CNT 0x0315
|
||||
#define regCLK1_CLK1_CURRENT_CNT_BASE_IDX 0
|
||||
#define regCLK1_CLK2_CURRENT_CNT 0x0316
|
||||
#define regCLK1_CLK2_CURRENT_CNT_BASE_IDX 0
|
||||
#define regCLK1_CLK3_CURRENT_CNT 0x0317
|
||||
#define regCLK1_CLK3_CURRENT_CNT_BASE_IDX 0
|
||||
#define regCLK1_CLK4_CURRENT_CNT 0x0318
|
||||
#define regCLK1_CLK4_CURRENT_CNT_BASE_IDX 0
|
||||
#define regCLK1_CLK5_CURRENT_CNT 0x0319
|
||||
#define regCLK1_CLK5_CURRENT_CNT_BASE_IDX 0
|
||||
|
||||
#define TO_CLK_MGR_DCN315(clk_mgr)\
|
||||
container_of(clk_mgr, struct clk_mgr_dcn315, base)
|
||||
|
||||
#define REG(reg_name) \
|
||||
(CLK_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
|
||||
|
||||
#define UNSUPPORTED_DCFCLK 10000000
|
||||
#define MIN_DPP_DISP_CLK 100000
|
||||
|
||||
|
|
@ -245,9 +279,38 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
|
|||
dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
|
||||
}
|
||||
|
||||
static void dcn315_dump_clk_registers_internal(struct dcn35_clk_internal *internal, struct clk_mgr *clk_mgr_base)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||
|
||||
// read dtbclk
|
||||
internal->CLK1_CLK4_CURRENT_CNT = REG_READ(CLK1_CLK4_CURRENT_CNT);
|
||||
|
||||
// read dcfclk
|
||||
internal->CLK1_CLK3_CURRENT_CNT = REG_READ(CLK1_CLK3_CURRENT_CNT);
|
||||
|
||||
// read dppclk
|
||||
internal->CLK1_CLK1_CURRENT_CNT = REG_READ(CLK1_CLK1_CURRENT_CNT);
|
||||
|
||||
// read dprefclk
|
||||
internal->CLK1_CLK2_CURRENT_CNT = REG_READ(CLK1_CLK2_CURRENT_CNT);
|
||||
|
||||
// read dispclk
|
||||
internal->CLK1_CLK0_CURRENT_CNT = REG_READ(CLK1_CLK0_CURRENT_CNT);
|
||||
}
|
||||
|
||||
static void dcn315_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
|
||||
struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
|
||||
{
|
||||
struct dcn35_clk_internal internal = {0};
|
||||
|
||||
dcn315_dump_clk_registers_internal(&internal, clk_mgr_base);
|
||||
|
||||
regs_and_bypass->dcfclk = internal.CLK1_CLK3_CURRENT_CNT / 10;
|
||||
regs_and_bypass->dprefclk = internal.CLK1_CLK2_CURRENT_CNT / 10;
|
||||
regs_and_bypass->dispclk = internal.CLK1_CLK0_CURRENT_CNT / 10;
|
||||
regs_and_bypass->dppclk = internal.CLK1_CLK1_CURRENT_CNT / 10;
|
||||
regs_and_bypass->dtbclk = internal.CLK1_CLK4_CURRENT_CNT / 10;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -594,13 +657,32 @@ static struct clk_mgr_funcs dcn315_funcs = {
|
|||
.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
|
||||
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
|
||||
.update_clocks = dcn315_update_clocks,
|
||||
.init_clocks = dcn31_init_clocks,
|
||||
.init_clocks = dcn315_init_clocks,
|
||||
.enable_pme_wa = dcn315_enable_pme_wa,
|
||||
.are_clock_states_equal = dcn31_are_clock_states_equal,
|
||||
.notify_wm_ranges = dcn315_notify_wm_ranges
|
||||
};
|
||||
extern struct clk_mgr_funcs dcn3_fpga_funcs;
|
||||
|
||||
void dcn315_init_clocks(struct clk_mgr *clk_mgr)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr);
|
||||
uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz;
|
||||
struct clk_mgr_dcn315 *clk_mgr_dcn315 = TO_CLK_MGR_DCN315(clk_mgr_int);
|
||||
struct clk_log_info log_info = {0};
|
||||
|
||||
memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
|
||||
// Assumption is that boot state always supports pstate
|
||||
clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk
|
||||
clk_mgr->clks.p_state_change_support = true;
|
||||
clk_mgr->clks.prev_p_state_change_support = true;
|
||||
clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN;
|
||||
clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN;
|
||||
|
||||
dcn315_dump_clk_registers(&clk_mgr->boot_snapshot, &clk_mgr_dcn315->base.base, &log_info);
|
||||
clk_mgr->clks.dispclk_khz = clk_mgr->boot_snapshot.dispclk * 1000;
|
||||
}
|
||||
|
||||
void dcn315_clk_mgr_construct(
|
||||
struct dc_context *ctx,
|
||||
struct clk_mgr_dcn315 *clk_mgr,
|
||||
|
|
@ -661,6 +743,7 @@ void dcn315_clk_mgr_construct(
|
|||
/* Saved clocks configured at boot for debug purposes */
|
||||
dcn315_dump_clk_registers(&clk_mgr->base.base.boot_snapshot,
|
||||
&clk_mgr->base.base, &log_info);
|
||||
clk_mgr->base.base.clks.dispclk_khz = clk_mgr->base.base.boot_snapshot.dispclk * 1000;
|
||||
|
||||
clk_mgr->base.base.dprefclk_khz = 600000;
|
||||
clk_mgr->base.base.dprefclk_khz = dcn315_smu_get_dpref_clk(&clk_mgr->base);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ void dcn315_clk_mgr_construct(struct dc_context *ctx,
|
|||
struct pp_smu_funcs *pp_smu,
|
||||
struct dccg *dccg);
|
||||
|
||||
void dcn315_init_clocks(struct clk_mgr *clk_mgr);
|
||||
void dcn315_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int);
|
||||
|
||||
#endif //__DCN315_CLK_MGR_H__
|
||||
|
|
|
|||
|
|
@ -889,6 +889,7 @@ static const struct dc_debug_options debug_defaults_drv = {
|
|||
},
|
||||
.psr_power_use_phy_fsm = 0,
|
||||
.using_dml2 = false,
|
||||
.min_disp_clk_khz = 100000,
|
||||
};
|
||||
|
||||
static const struct dc_check_config config_defaults = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user