Commit 5b880e37 authored by Roman Li's avatar Roman Li Committed by Alex Deucher
Browse files

drm/amd/display: Enable dcn42 DC clk_mgr



Add support for DCN 4.2 clock manager.

Acked-by: default avatarAurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: default avatarRoman Li <Roman.Li@amd.com>
Signed-off-by: default avatarAlex Hung <alex.hung@amd.com>
Tested-by: default avatarDan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8c993dad
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#include "dcn32/dcn32_clk_mgr.h"
#include "dcn35/dcn35_clk_mgr.h"
#include "dcn401/dcn401_clk_mgr.h"
#include "dcn42/dcn42_clk_mgr.h"

int clk_mgr_helper_get_active_display_cnt(
		struct dc *dc,
@@ -362,6 +363,18 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
		return &clk_mgr->base;
	}
	break;
	case AMDGPU_FAMILY_GC_11_5_4: {
		struct clk_mgr_dcn42 *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL);

		if (clk_mgr == NULL) {
			BREAK_TO_DEBUGGER();
			return NULL;
		}

		dcn42_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
		return &clk_mgr->base.base;
	}
	break;
#endif	/* CONFIG_DRM_AMD_DC_FP */
	default:
		ASSERT(0); /* Unknown Asic */
@@ -419,6 +432,9 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base)
	case AMDGPU_FAMILY_GC_12_0_0:
		dcn401_clk_mgr_destroy(clk_mgr);
		break;
	case AMDGPU_FAMILY_GC_11_5_4:
		dcn42_clk_mgr_destroy(clk_mgr);
		break;

	default:
		break;
+119 −117
Original line number Diff line number Diff line
@@ -31,59 +31,19 @@
#include "link_service.h"
#include "logger_types.h"

#include "clk/clk_15_0_0_offset.h"
#include "clk/clk_15_0_0_sh_mask.h"
#include "dcn/dcn_4_2_0_offset.h"
#include "dcn/dcn_4_2_0_sh_mask.h"


#undef DC_LOGGER
#define DC_LOGGER \
	clk_mgr->base.base.ctx->logger


#define DCN_BASE__INST0_SEG1                       0x000000C0

#define regCLK8_CLK2_BYPASS_CNTL			 0x4c2a
#define regCLK8_CLK2_BYPASS_CNTL_BASE_IDX	0
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL__SHIFT	0x0
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV__SHIFT	0x10
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK		0x00000007L
#define CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV_MASK		0x000F0000L

#define regDENTIST_DISPCLK_CNTL 0x0064
#define regDENTIST_DISPCLK_CNTL_BASE_IDX 1

// DENTIST_DISPCLK_CNTL
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_WDIVIDER__SHIFT 0x0
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_RDIVIDER__SHIFT 0x8
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_CHG_DONE__SHIFT 0x13
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_CHG_DONE__SHIFT 0x14
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_WDIVIDER__SHIFT 0x18
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_WDIVIDER_MASK 0x0000007FL
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_RDIVIDER_MASK 0x00007F00L
#define DENTIST_DISPCLK_CNTL__DENTIST_DISPCLK_CHG_DONE_MASK 0x00080000L
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_CHG_DONE_MASK 0x00100000L
#define DENTIST_DISPCLK_CNTL__DENTIST_DPPCLK_WDIVIDER_MASK 0x7F000000L
#define mmDENTIST_DISPCLK_CNTL 0x0124
#define mmCLK8_CLK_TICK_CNT_CONFIG_REG                  0x1B851
#define mmCLK8_CLK0_CURRENT_CNT                         0x1B853
#define mmCLK8_CLK1_CURRENT_CNT                         0x1B854
#define mmCLK8_CLK2_CURRENT_CNT                         0x1B855
#define mmCLK8_CLK3_CURRENT_CNT                         0x1B856
#define mmCLK8_CLK4_CURRENT_CNT                         0x1B857


#define mmCLK8_CLK0_BYPASS_CNTL                         0x1B81A
#define mmCLK8_CLK1_BYPASS_CNTL                         0x1B822
#define mmCLK8_CLK2_BYPASS_CNTL                         0x1B82A
#define mmCLK8_CLK3_BYPASS_CNTL                         0x1B832
#define mmCLK8_CLK4_BYPASS_CNTL                         0x1B83A


#define mmCLK8_CLK0_DS_CNTL                             0x1B814
#define mmCLK8_CLK1_DS_CNTL                             0x1B81C
#define mmCLK8_CLK2_DS_CNTL                             0x1B824
#define mmCLK8_CLK3_DS_CNTL                             0x1B82C
#define mmCLK8_CLK4_DS_CNTL                             0x1B834


	dc_logger
#define DC_LOGGER_INIT(logger) \
	struct dal_logger *dc_logger = logger

#define DCN42_CLKIP_REFCLK 48000

#undef FN
#define FN(reg_name, field_name) \
@@ -92,16 +52,25 @@
#define REG(reg) \
	(clk_mgr->regs->reg)

// for DCN register access
#define DCN_BASE__INST0_SEG0 0x00000012
#define DCN_BASE__INST0_SEG1 0x000000C0

#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg

#define BASE(seg) BASE_INNER(seg)

#define SR(reg_name) \
		.reg_name = BASE(reg ## reg_name ## _BASE_IDX) +  \
					reg ## reg_name
	.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name

// for CLKIP register access
#define CLK_BASE__INST0_SEG0 0x00016C00

#define CLK_BASE_INNER(seg) \
	CLK_BASE__INST0_SEG ## seg

#define CLK_SR_DCN42(reg_name) \
	.reg_name = mm ## reg_name
	.reg_name = CLK_BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name

static const struct clk_mgr_registers clk_mgr_regs_dcn42 = {
	CLK_REG_LIST_DCN42()
@@ -115,8 +84,6 @@ static const struct clk_mgr_mask clk_mgr_mask_dcn42 = {
	CLK_COMMON_MASK_SH_LIST_DCN42(_MASK)
};



#define TO_CLK_MGR_DCN42(clk_mgr_int)\
	container_of(clk_mgr_int, struct clk_mgr_dcn42, base)

@@ -154,6 +121,49 @@ int dcn42_get_active_display_cnt_wa(
	return display_count;
}

static uint32_t dcn42_get_clock_freq_from_clkip(struct clk_mgr *clk_mgr_base, enum clock_type clock)
{
	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
	uint64_t clock_freq_mhz = 0;
	uint32_t timer_threshold = 0;

	// always safer to read the timer threshold instead of using cached value
	REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &timer_threshold);

	if (timer_threshold == 0) {
		BREAK_TO_DEBUGGER();
		return 0;
	}

	switch (clock) {
	case clock_type_dispclk:
		clock_freq_mhz = REG_READ(CLK8_CLK0_CURRENT_CNT);
		break;
	case clock_type_dppclk:
		clock_freq_mhz = REG_READ(CLK8_CLK1_CURRENT_CNT);
		break;
	case clock_type_dprefclk:
		clock_freq_mhz = REG_READ(CLK8_CLK2_CURRENT_CNT);
		break;
	case clock_type_dcfclk:
		clock_freq_mhz = REG_READ(CLK8_CLK3_CURRENT_CNT);
		break;
	case clock_type_dtbclk:
		clock_freq_mhz = REG_READ(CLK8_CLK4_CURRENT_CNT);
		break;
	default:
		break;
	}

	clock_freq_mhz *= DCN42_CLKIP_REFCLK;
	clock_freq_mhz = div_u64(clock_freq_mhz, timer_threshold);

	// there are no DCN clocks over 0xFFFFFFFF MHz
	ASSERT(clock_freq_mhz <= 0xFFFFFFFF);

	return (uint32_t)clock_freq_mhz;
}

void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
		struct dc_state *context,
		int ref_dtbclk_khz)
@@ -224,8 +234,6 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,

	display_count = dcn42_get_active_display_cnt_wa(dc, context, &all_active_disps);

	/*dml21 issue*/
	ASSERT(new_clocks->dtbclk_en && new_clocks->ref_dtbclk_khz > 590000); //remove this section if assert is hit
	if (new_clocks->dtbclk_en && new_clocks->ref_dtbclk_khz < 590000)
		new_clocks->ref_dtbclk_khz = 600000;

@@ -262,9 +270,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,

			dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
			dcn42_smu_set_dtbclk(clk_mgr, true);
			if (clk_mgr_base->boot_snapshot.timer_threhold)
				actual_dtbclk = REG_READ(CLK8_CLK4_CURRENT_CNT) / (clk_mgr_base->boot_snapshot.timer_threhold / 48000);

			actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);

			if (actual_dtbclk > 590000) {
				clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
@@ -386,44 +392,40 @@ bool dcn42_are_clock_states_equal(struct dc_clocks *a,
static void dcn42_dump_clk_registers_internal(struct dcn42_clk_internal *internal, struct clk_mgr *clk_mgr_base)
{
	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
	uint32_t ratio = 1;

	internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD = REG_READ(CLK8_CLK_TICK_CNT_CONFIG_REG) & 0xFFFFFF;

	ratio = internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD / 48000;
	ASSERT(ratio != 0);
	REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD);

	if (ratio) {
	// read dcf deep sleep divider
	internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL);
	internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL);
	// read dispclk
		internal->CLK8_CLK0_CURRENT_CNT = REG_READ(CLK8_CLK0_CURRENT_CNT) / ratio;
	internal->CLK8_CLK0_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dispclk);
	internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL);
	// read dppclk
		internal->CLK8_CLK1_CURRENT_CNT = REG_READ(CLK8_CLK1_CURRENT_CNT) / ratio;
	internal->CLK8_CLK1_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dppclk);
	internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL);
	// read dprefclk
		internal->CLK8_CLK2_CURRENT_CNT = REG_READ(CLK8_CLK2_CURRENT_CNT) / ratio;
	internal->CLK8_CLK2_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dprefclk);
	internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL);
	// read dcfclk
		internal->CLK8_CLK3_CURRENT_CNT = REG_READ(CLK8_CLK3_CURRENT_CNT) / ratio;
	internal->CLK8_CLK3_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dcfclk);
	internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL);
	// read dtbclk
		internal->CLK8_CLK4_CURRENT_CNT = REG_READ(CLK8_CLK4_CURRENT_CNT) / ratio;
	internal->CLK8_CLK4_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
	internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL);
}

}

static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
		struct clk_mgr_dcn42 *clk_mgr)
{
	struct dcn42_clk_internal internal = {0};
	char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"};

	DC_LOGGER_INIT(clk_mgr->base.base.ctx->logger);
	(void)dc_logger;

	dcn42_dump_clk_registers_internal(&internal, &clk_mgr->base.base);
	regs_and_bypass->timer_threhold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
	regs_and_bypass->timer_threshold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD;
	regs_and_bypass->dcfclk = internal.CLK8_CLK3_CURRENT_CNT / 10;
	regs_and_bypass->dcf_deep_sleep_divider = internal.CLK8_CLK3_DS_CNTL / 10;
	regs_and_bypass->dcf_deep_sleep_allow = internal.CLK8_CLK3_DS_CNTL & 0x10; /*bit 4: CLK0_ALLOW_DS*/
@@ -432,18 +434,10 @@ static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs
	regs_and_bypass->dppclk = internal.CLK8_CLK1_CURRENT_CNT / 10;
	regs_and_bypass->dtbclk = internal.CLK8_CLK4_CURRENT_CNT / 10;

	regs_and_bypass->dppclk_bypass = internal.CLK8_CLK1_BYPASS_CNTL & 0x0007;
	if (regs_and_bypass->dppclk_bypass > 4)
		regs_and_bypass->dppclk_bypass = 0;
	regs_and_bypass->dcfclk_bypass = internal.CLK8_CLK3_BYPASS_CNTL & 0x0007;
	if (regs_and_bypass->dcfclk_bypass > 4)
		regs_and_bypass->dcfclk_bypass = 0;
	regs_and_bypass->dispclk_bypass = internal.CLK8_CLK0_BYPASS_CNTL & 0x0007;
	if (regs_and_bypass->dispclk_bypass > 4)
		regs_and_bypass->dispclk_bypass = 0;
	regs_and_bypass->dprefclk_bypass = internal.CLK8_CLK2_BYPASS_CNTL & 0x0007;
	if (regs_and_bypass->dprefclk_bypass > 4)
		regs_and_bypass->dprefclk_bypass = 0;
	regs_and_bypass->dispclk_bypass = get_reg_field_value(internal.CLK8_CLK0_BYPASS_CNTL, CLK8_CLK0_BYPASS_CNTL, CLK0_BYPASS_SEL);
	regs_and_bypass->dppclk_bypass = get_reg_field_value(internal.CLK8_CLK1_BYPASS_CNTL, CLK8_CLK1_BYPASS_CNTL, CLK1_BYPASS_SEL);
	regs_and_bypass->dprefclk_bypass = get_reg_field_value(internal.CLK8_CLK2_BYPASS_CNTL, CLK8_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL);
	regs_and_bypass->dcfclk_bypass = get_reg_field_value(internal.CLK8_CLK3_BYPASS_CNTL, CLK8_CLK3_BYPASS_CNTL, CLK3_BYPASS_SEL);

	if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
		DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n");
@@ -588,6 +582,9 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
	struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int);
	struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 };

	DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
	(void)dc_logger;

	init_clk_states(clk_mgr_base);

	// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
@@ -1112,6 +1109,9 @@ void dcn42_clk_mgr_construct(
	clk_mgr->base.base.dprefclk_khz = 600000;

	clk_mgr->base.smu_present = false;
	clk_mgr->base.smu_ver = dcn42_smu_get_pmfw_version(&clk_mgr->base);
	if (clk_mgr->base.smu_ver && clk_mgr->base.smu_ver != -1)
		clk_mgr->base.smu_present = true;

	if (ctx->dc_bios->integrated_info) {
		clk_mgr->base.base.dentist_vco_freq_khz = ctx->dc_bios->integrated_info->dentist_vco_freq;
@@ -1120,10 +1120,12 @@ void dcn42_clk_mgr_construct(
			dcn42_bw_params.wm_table = lpddr5_wm_table;
		else
			dcn42_bw_params.wm_table = ddr5_wm_table;

		dcn42_bw_params.vram_type = ctx->dc_bios->integrated_info->memory_type;
		dcn42_bw_params.dram_channel_width_bytes = ctx->dc_bios->integrated_info->memory_type == 0x22 ? 8 : 4;
		dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 4;
	}

	/* in case we don't get a value from the BIOS, use default */
	if (clk_mgr->base.base.dentist_vco_freq_khz == 0)
		clk_mgr->base.base.dentist_vco_freq_khz = 3000000; /* 3000MHz */
+1 −0
Original line number Diff line number Diff line
@@ -5945,6 +5945,7 @@ bool dc_is_dmub_outbox_supported(struct dc *dc)

	case AMDGPU_FAMILY_GC_11_0_1:
	case AMDGPU_FAMILY_GC_11_5_0:
	case AMDGPU_FAMILY_GC_11_5_4:
		if (!dc->debug.dpia_debug.bits.disable_dpia)
			return true;
	break;
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl
		spl_in->callbacks = dcn32_spl_callbacks;
		break;
	case DCN_VERSION_4_01:
	case DCN_VERSION_4_2:
		spl_in->callbacks = dcn401_spl_callbacks;
		break;
	default:
+2 −1
Original line number Diff line number Diff line
@@ -374,7 +374,8 @@
	type OTG1_DROP_PIXEL;\
	type OTG2_DROP_PIXEL;\
	type OTG3_ADD_PIXEL;\
	type OTG3_DROP_PIXEL;
	type OTG3_DROP_PIXEL;\
	type RESYNC_FIFO_LEVEL_ADJUST_EN;

struct dccg_shift {
	DCCG_REG_FIELD_LIST(uint8_t)
Loading