xref: /linux/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c (revision 1fc5a74b108fc90951890ec513ac81869f5eaff1)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2025 Advanced Micro Devices, Inc.
4 
5 #include "reg_helper.h"
6 #include "core_types.h"
7 #include "dcn42/dcn42_dccg.h"
8 #include "dcn60_dccg.h"
9 
10 #define TO_DCN_DCCG(dccg)\
11 	container_of(dccg, struct dcn_dccg, base)
12 
13 #define REG(reg) \
14 	(dccg_dcn->regs->reg)
15 
16 #undef FN
17 #define FN(reg_name, field_name) \
18 	dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
19 
20 #define CTX \
21 	dccg_dcn->base.ctx
22 #define DC_LOGGER \
23 	dccg->ctx->logger
24 
dccg60_set_pixel_rate_div(struct dccg * dccg,uint32_t otg_inst,enum pixel_rate_div tmds_div,enum pixel_rate_div unused)25 static void dccg60_set_pixel_rate_div(
26 		struct dccg *dccg,
27 		uint32_t otg_inst,
28 		enum pixel_rate_div tmds_div,
29 		enum pixel_rate_div unused)
30 {
31 	(void)unused;
32 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
33 	uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
34 	uint32_t dp_dto_int;
35 	uint32_t reg_val;
36 
37 	// only 2 is valid on dcn401
38 	if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
39 		return;
40 	}
41 
42 	dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
43 	if (tmds_div == cur_tmds_div)
44 		return;
45 
46 	// encode enum to register value
47 	reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
48 
49 	switch (otg_inst) {
50 	case 0:
51 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
52 				OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
53 		break;
54 	case 1:
55 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
56 				OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
57 		break;
58 	case 2:
59 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
60 				OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
61 		break;
62 	case 3:
63 		REG_UPDATE(OTG_PIXEL_RATE_DIV,
64 				OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
65 		break;
66 	default:
67 		BREAK_TO_DEBUGGER();
68 		return;
69 	}
70 }
71 
dccg60_set_dto_dscclk(struct dccg * dccg,uint32_t inst,uint32_t num_slices_h)72 static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst,
73 		uint32_t num_slices_h)
74 {
75 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
76 
77 	switch (inst) {
78 	case 0:
79 		REG_UPDATE_2(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, 1,
80 				DSCCLK0_DTO_MODULO, 1);
81 		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);
82 
83 		/*
84 		 * Source for dscclk should be set when dto tuned clock is used.
85 		 * For 1 slice config, set src to dprefclk.
86 		 * For 2 or more slice config, set src to dispclk.
87 		 */
88 		if (num_slices_h == 1)
89 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 1);
90 		else
91 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 0);
92 
93 		break;
94 	case 1:
95 		REG_UPDATE_2(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, 1,
96 				DSCCLK1_DTO_MODULO, 1);
97 		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
98 
99 		if (num_slices_h == 1)
100 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 1);
101 		else
102 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 0);
103 
104 		break;
105 	case 2:
106 		REG_UPDATE_2(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, 1,
107 				DSCCLK2_DTO_MODULO, 1);
108 		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
109 
110 		if (num_slices_h == 1)
111 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 1);
112 		else
113 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 0);
114 
115 		break;
116 	case 3:
117 		REG_UPDATE_2(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, 1,
118 				DSCCLK3_DTO_MODULO, 1);
119 		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);
120 
121 		if (num_slices_h == 1)
122 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 1);
123 		else
124 			REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 0);
125 
126 		break;
127 	default:
128 		BREAK_TO_DEBUGGER();
129 		return;
130 	}
131 }
132 
133 static const struct dccg_funcs dccg60_funcs = {
134 	.enable_hdmicharclk = dccg401_enable_hdmicharclk,
135 	.disable_hdmicharclk = dccg401_disable_hdmicharclk,
136 	.set_hdmistreamclk = dccg401_set_hdmistreamclk,
137 	.update_dpp_dto = dccg401_update_dpp_dto,
138 	.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
139 	.dccg_init = dccg401_init,
140 	.set_dpstreamclk = dccg401_set_dpstreamclk,
141 	.enable_symclk32_se = dccg31_enable_symclk32_se,
142 	.disable_symclk32_se = dccg31_disable_symclk32_se,
143 	.enable_symclk32_le = dccg401_enable_symclk32_le,
144 	.disable_symclk32_le = dccg401_disable_symclk32_le,
145 	.set_physymclk = dccg401_set_physymclk,
146 	.set_dtbclk_dto = NULL,
147 	.set_dto_dscclk = dccg60_set_dto_dscclk,
148 	.set_ref_dscclk = dccg401_set_ref_dscclk,
149 	.set_valid_pixel_rate = NULL,
150 	.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
151 	.set_audio_dtbclk_dto = NULL,
152 	.otg_add_pixel = dccg42_otg_add_pixel,
153 	.otg_drop_pixel = dccg42_otg_drop_pixel,
154 	.set_pixel_rate_div = dccg60_set_pixel_rate_div,
155 	.get_pixel_rate_div = dccg401_get_pixel_rate_div,
156 	.set_dp_dto = dccg401_set_dp_dto,
157 	.enable_symclk_se = dccg401_enable_symclk_se,
158 	.disable_symclk_se = dccg401_disable_symclk_se,
159 	.set_dtbclk_p_src = dccg401_set_dtbclk_p_src,
160 	.dccg_read_reg_state = dccg31_read_reg_state,
161 	.allow_clock_gating = dccg2_allow_clock_gating
162 };
163 
dccg60_create(struct dc_context * ctx,const struct dccg_registers * regs,const struct dccg_shift * dccg_shift,const struct dccg_mask * dccg_mask)164 struct dccg *dccg60_create(
165 	struct dc_context *ctx,
166 	const struct dccg_registers *regs,
167 	const struct dccg_shift *dccg_shift,
168 	const struct dccg_mask *dccg_mask)
169 {
170 	struct dcn_dccg *dccg_dcn = kzalloc_obj(*dccg_dcn);
171 	struct dccg *base;
172 
173 	if (dccg_dcn == NULL) {
174 		BREAK_TO_DEBUGGER();
175 		return NULL;
176 	}
177 
178 	base = &dccg_dcn->base;
179 	base->ctx = ctx;
180 	base->funcs = &dccg60_funcs;
181 
182 	dccg_dcn->regs = regs;
183 	dccg_dcn->dccg_shift = dccg_shift;
184 	dccg_dcn->dccg_mask = dccg_mask;
185 
186 	return &dccg_dcn->base;
187 }
188