• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "reg_helper.h"
27 #include "core_types.h"
28 #include "dcn31_dccg.h"
29 
30 #define TO_DCN_DCCG(dccg)\
31 	container_of(dccg, struct dcn_dccg, base)
32 
33 #define REG(reg) \
34 	(dccg_dcn->regs->reg)
35 
36 #undef FN
37 #define FN(reg_name, field_name) \
38 	dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
39 
40 #define CTX \
41 	dccg_dcn->base.ctx
42 #define DC_LOGGER \
43 	dccg->ctx->logger
44 
dccg31_set_physymclk(struct dccg * dccg,int phy_inst,enum physymclk_clock_source clk_src,bool force_enable)45 void dccg31_set_physymclk(
46 		struct dccg *dccg,
47 		int phy_inst,
48 		enum physymclk_clock_source clk_src,
49 		bool force_enable)
50 {
51 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
52 
53 	/* Force PHYSYMCLK on and Select phyd32clk as the source of clock which is output to PHY through DCIO */
54 	switch (phy_inst) {
55 	case 0:
56 		if (force_enable)
57 			REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
58 					PHYASYMCLK_FORCE_EN, 1,
59 					PHYASYMCLK_FORCE_SRC_SEL, clk_src);
60 		else
61 			REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
62 					PHYASYMCLK_FORCE_EN, 0,
63 					PHYASYMCLK_FORCE_SRC_SEL, 0);
64 		break;
65 	case 1:
66 		if (force_enable)
67 			REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
68 					PHYBSYMCLK_FORCE_EN, 1,
69 					PHYBSYMCLK_FORCE_SRC_SEL, clk_src);
70 		else
71 			REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
72 					PHYBSYMCLK_FORCE_EN, 0,
73 					PHYBSYMCLK_FORCE_SRC_SEL, 0);
74 		break;
75 	case 2:
76 		if (force_enable)
77 			REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
78 					PHYCSYMCLK_FORCE_EN, 1,
79 					PHYCSYMCLK_FORCE_SRC_SEL, clk_src);
80 		else
81 			REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
82 					PHYCSYMCLK_FORCE_EN, 0,
83 					PHYCSYMCLK_FORCE_SRC_SEL, 0);
84 		break;
85 	case 3:
86 		if (force_enable)
87 			REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
88 					PHYDSYMCLK_FORCE_EN, 1,
89 					PHYDSYMCLK_FORCE_SRC_SEL, clk_src);
90 		else
91 			REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
92 					PHYDSYMCLK_FORCE_EN, 0,
93 					PHYDSYMCLK_FORCE_SRC_SEL, 0);
94 		break;
95 	case 4:
96 		if (force_enable)
97 			REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
98 					PHYESYMCLK_FORCE_EN, 1,
99 					PHYESYMCLK_FORCE_SRC_SEL, clk_src);
100 		else
101 			REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
102 					PHYESYMCLK_FORCE_EN, 0,
103 					PHYESYMCLK_FORCE_SRC_SEL, 0);
104 		break;
105 	default:
106 		BREAK_TO_DEBUGGER();
107 		return;
108 	}
109 }
110 
111 /* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */
dccg31_set_dtbclk_dto(struct dccg * dccg,int dtbclk_inst,int req_dtbclk_khz,int num_odm_segments,const struct dc_crtc_timing * timing)112 void dccg31_set_dtbclk_dto(
113 		struct dccg *dccg,
114 		int dtbclk_inst,
115 		int req_dtbclk_khz,
116 		int num_odm_segments,
117 		const struct dc_crtc_timing *timing)
118 {
119 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
120 	uint32_t dtbdto_div;
121 
122 	/* Mode	                DTBDTO Rate       DTBCLK_DTO<x>_DIV Register
123 	 * ODM 4:1 combine      pixel rate/4      2
124 	 * ODM 2:1 combine      pixel rate/2      4
125 	 * non-DSC 4:2:0 mode   pixel rate/2      4
126 	 * DSC native 4:2:0     pixel rate/2      4
127 	 * DSC native 4:2:2     pixel rate/2      4
128 	 * Other modes          pixel rate        8
129 	 */
130 	if (num_odm_segments == 4) {
131 		dtbdto_div = 2;
132 		req_dtbclk_khz = req_dtbclk_khz / 4;
133 	} else if ((num_odm_segments == 2) ||
134 			(timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ||
135 			(timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
136 					&& !timing->dsc_cfg.ycbcr422_simple)) {
137 		dtbdto_div = 4;
138 		req_dtbclk_khz = req_dtbclk_khz / 2;
139 	} else
140 		dtbdto_div = 8;
141 
142 	if (dccg->ref_dtbclk_khz && req_dtbclk_khz) {
143 		uint32_t modulo, phase;
144 
145 		// phase / modulo = dtbclk / dtbclk ref
146 		modulo = dccg->ref_dtbclk_khz * 1000;
147 		phase = div_u64((((unsigned long long)modulo * req_dtbclk_khz) + dccg->ref_dtbclk_khz - 1),
148 			dccg->ref_dtbclk_khz);
149 
150 		REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
151 				DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div);
152 
153 		REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], modulo);
154 		REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], phase);
155 
156 		REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
157 				DTBCLK_DTO_ENABLE[dtbclk_inst], 1);
158 
159 		REG_WAIT(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
160 				DTBCLKDTO_ENABLE_STATUS[dtbclk_inst], 1,
161 				1, 100);
162 
163 		/* The recommended programming sequence to enable DTBCLK DTO to generate
164 		 * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should
165 		 * be set only after DTO is enabled
166 		 */
167 		REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
168 				PIPE_DTO_SRC_SEL[dtbclk_inst], 1);
169 
170 		dccg->dtbclk_khz[dtbclk_inst] = req_dtbclk_khz;
171 	} else {
172 		REG_UPDATE_3(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
173 				DTBCLK_DTO_ENABLE[dtbclk_inst], 0,
174 				PIPE_DTO_SRC_SEL[dtbclk_inst], 0,
175 				DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div);
176 
177 		REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], 0);
178 		REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], 0);
179 
180 		dccg->dtbclk_khz[dtbclk_inst] = 0;
181 	}
182 }
183 
dccg31_set_audio_dtbclk_dto(struct dccg * dccg,uint32_t req_audio_dtbclk_khz)184 void dccg31_set_audio_dtbclk_dto(
185 		struct dccg *dccg,
186 		uint32_t req_audio_dtbclk_khz)
187 {
188 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
189 
190 	if (dccg->ref_dtbclk_khz && req_audio_dtbclk_khz) {
191 		uint32_t modulo, phase;
192 
193 		// phase / modulo = dtbclk / dtbclk ref
194 		modulo = dccg->ref_dtbclk_khz * 1000;
195 		phase = div_u64((((unsigned long long)modulo * req_audio_dtbclk_khz) + dccg->ref_dtbclk_khz - 1),
196 			dccg->ref_dtbclk_khz);
197 
198 
199 		REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, modulo);
200 		REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, phase);
201 
202 		//REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
203 		//		DCCG_AUDIO_DTBCLK_DTO_USE_512FBR_DTO, 1);
204 
205 		REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
206 				DCCG_AUDIO_DTO_SEL, 4);  //  04 - DCCG_AUDIO_DTO_SEL_AUDIO_DTO_DTBCLK
207 
208 		dccg->audio_dtbclk_khz = req_audio_dtbclk_khz;
209 	} else {
210 		REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, 0);
211 		REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, 0);
212 
213 		REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
214 				DCCG_AUDIO_DTO_SEL, 3);  //  03 - DCCG_AUDIO_DTO_SEL_NO_AUDIO_DTO
215 
216 		dccg->audio_dtbclk_khz = 0;
217 	}
218 }
219 
dccg31_get_dccg_ref_freq(struct dccg * dccg,unsigned int xtalin_freq_inKhz,unsigned int * dccg_ref_freq_inKhz)220 static void dccg31_get_dccg_ref_freq(struct dccg *dccg,
221 		unsigned int xtalin_freq_inKhz,
222 		unsigned int *dccg_ref_freq_inKhz)
223 {
224 	/*
225 	 * Assume refclk is sourced from xtalin
226 	 * expect 24MHz
227 	 */
228 	*dccg_ref_freq_inKhz = xtalin_freq_inKhz;
229 	return;
230 }
231 
dccg31_set_dispclk_change_mode(struct dccg * dccg,enum dentist_dispclk_change_mode change_mode)232 static void dccg31_set_dispclk_change_mode(
233 	struct dccg *dccg,
234 	enum dentist_dispclk_change_mode change_mode)
235 {
236 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
237 
238 	REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE,
239 		   change_mode == DISPCLK_CHANGE_MODE_RAMPING ? 2 : 0);
240 }
241 
dccg31_init(struct dccg * dccg)242 void dccg31_init(struct dccg *dccg)
243 {
244 }
245 
246 static const struct dccg_funcs dccg31_funcs = {
247 	.update_dpp_dto = dccg2_update_dpp_dto,
248 	.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
249 	.dccg_init = dccg31_init,
250 	.set_physymclk = dccg31_set_physymclk,
251 	.set_dtbclk_dto = dccg31_set_dtbclk_dto,
252 	.set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,
253 	.set_dispclk_change_mode = dccg31_set_dispclk_change_mode,
254 };
255 
dccg31_create(struct dc_context * ctx,const struct dccg_registers * regs,const struct dccg_shift * dccg_shift,const struct dccg_mask * dccg_mask)256 struct dccg *dccg31_create(
257 	struct dc_context *ctx,
258 	const struct dccg_registers *regs,
259 	const struct dccg_shift *dccg_shift,
260 	const struct dccg_mask *dccg_mask)
261 {
262 	struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
263 	struct dccg *base;
264 
265 	if (dccg_dcn == NULL) {
266 		BREAK_TO_DEBUGGER();
267 		return NULL;
268 	}
269 
270 	base = &dccg_dcn->base;
271 	base->ctx = ctx;
272 	base->funcs = &dccg31_funcs;
273 
274 	dccg_dcn->regs = regs;
275 	dccg_dcn->dccg_shift = dccg_shift;
276 	dccg_dcn->dccg_mask = dccg_mask;
277 
278 	return &dccg_dcn->base;
279 }
280