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