1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2016 BayLibre, SAS |
4 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
5 | * Copyright (C) 2015 Amlogic, Inc. All rights reserved. |
6 | */ |
7 | |
8 | #include <linux/export.h> |
9 | |
10 | #include <drm/drm_print.h> |
11 | |
12 | #include "meson_drv.h" |
13 | #include "meson_vclk.h" |
14 | |
15 | /** |
16 | * DOC: Video Clocks |
17 | * |
18 | * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL. |
19 | * We handle the following encodings : |
20 | * |
21 | * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks |
22 | * - HDMI Pixel Clocks generation |
23 | * |
24 | * What is missing : |
25 | * |
26 | * - Genenate Pixel clocks for 2K/4K 10bit formats |
27 | * |
28 | * Clock generator scheme : |
29 | * |
30 | * .. code:: |
31 | * |
32 | * __________ _________ _____ |
33 | * | | | | | |--ENCI |
34 | * | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL |
35 | * |__________| |_________| \ | MUX |--ENCP |
36 | * --VCLK2-| |--VDAC |
37 | * |_____|--HDMI-TX |
38 | * |
39 | * Final clocks can take input for either VCLK or VCLK2, but |
40 | * VCLK is the preferred path for HDMI clocking and VCLK2 is the |
41 | * preferred path for CVBS VDAC clocking. |
42 | * |
43 | * VCLK and VCLK2 have fixed divided clocks paths for /1, /2, /4, /6 or /12. |
44 | * |
45 | * The PLL_DIV can achieve an additional fractional dividing like |
46 | * 1.5, 3.5, 3.75... to generate special 2K and 4K 10bit clocks. |
47 | */ |
48 | |
49 | /* HHI Registers */ |
50 | #define HHI_VID_PLL_CLK_DIV 0x1a0 /* 0x68 offset in data sheet */ |
51 | #define VID_PLL_EN BIT(19) |
52 | #define VID_PLL_BYPASS BIT(18) |
53 | #define VID_PLL_PRESET BIT(15) |
54 | #define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ |
55 | #define VCLK2_DIV_MASK 0xff |
56 | #define VCLK2_DIV_EN BIT(16) |
57 | #define VCLK2_DIV_RESET BIT(17) |
58 | #define CTS_VDAC_SEL_MASK (0xf << 28) |
59 | #define CTS_VDAC_SEL_SHIFT 28 |
60 | #define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ |
61 | #define VCLK2_EN BIT(19) |
62 | #define VCLK2_SEL_MASK (0x7 << 16) |
63 | #define VCLK2_SEL_SHIFT 16 |
64 | #define VCLK2_SOFT_RESET BIT(15) |
65 | #define VCLK2_DIV1_EN BIT(0) |
66 | #define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ |
67 | #define VCLK_DIV_MASK 0xff |
68 | #define VCLK_DIV_EN BIT(16) |
69 | #define VCLK_DIV_RESET BIT(17) |
70 | #define CTS_ENCP_SEL_MASK (0xf << 24) |
71 | #define CTS_ENCP_SEL_SHIFT 24 |
72 | #define CTS_ENCI_SEL_MASK (0xf << 28) |
73 | #define CTS_ENCI_SEL_SHIFT 28 |
74 | #define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ |
75 | #define VCLK_EN BIT(19) |
76 | #define VCLK_SEL_MASK (0x7 << 16) |
77 | #define VCLK_SEL_SHIFT 16 |
78 | #define VCLK_SOFT_RESET BIT(15) |
79 | #define VCLK_DIV1_EN BIT(0) |
80 | #define VCLK_DIV2_EN BIT(1) |
81 | #define VCLK_DIV4_EN BIT(2) |
82 | #define VCLK_DIV6_EN BIT(3) |
83 | #define VCLK_DIV12_EN BIT(4) |
84 | #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ |
85 | #define CTS_ENCI_EN BIT(0) |
86 | #define CTS_ENCP_EN BIT(2) |
87 | #define CTS_VDAC_EN BIT(4) |
88 | #define HDMI_TX_PIXEL_EN BIT(5) |
89 | #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ |
90 | #define HDMI_TX_PIXEL_SEL_MASK (0xf << 16) |
91 | #define HDMI_TX_PIXEL_SEL_SHIFT 16 |
92 | #define CTS_HDMI_SYS_SEL_MASK (0x7 << 9) |
93 | #define CTS_HDMI_SYS_DIV_MASK (0x7f) |
94 | #define CTS_HDMI_SYS_EN BIT(8) |
95 | |
96 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ |
97 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ |
98 | |
99 | #define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ |
100 | #define HHI_HDMI_PLL_CNTL_EN BIT(30) |
101 | #define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ |
102 | #define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ |
103 | #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ |
104 | #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ |
105 | #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ |
106 | #define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */ |
107 | |
108 | #define HDMI_PLL_RESET BIT(28) |
109 | #define HDMI_PLL_RESET_G12A BIT(29) |
110 | #define HDMI_PLL_LOCK BIT(31) |
111 | #define HDMI_PLL_LOCK_G12A (3 << 30) |
112 | |
113 | #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001) |
114 | |
115 | /* VID PLL Dividers */ |
116 | enum { |
117 | VID_PLL_DIV_1 = 0, |
118 | VID_PLL_DIV_2, |
119 | VID_PLL_DIV_2p5, |
120 | VID_PLL_DIV_3, |
121 | VID_PLL_DIV_3p5, |
122 | VID_PLL_DIV_3p75, |
123 | VID_PLL_DIV_4, |
124 | VID_PLL_DIV_5, |
125 | VID_PLL_DIV_6, |
126 | VID_PLL_DIV_6p25, |
127 | VID_PLL_DIV_7, |
128 | VID_PLL_DIV_7p5, |
129 | VID_PLL_DIV_12, |
130 | VID_PLL_DIV_14, |
131 | VID_PLL_DIV_15, |
132 | }; |
133 | |
134 | static void meson_vid_pll_set(struct meson_drm *priv, unsigned int div) |
135 | { |
136 | unsigned int shift_val = 0; |
137 | unsigned int shift_sel = 0; |
138 | |
139 | /* Disable vid_pll output clock */ |
140 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, val: 0); |
141 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, val: 0); |
142 | |
143 | switch (div) { |
144 | case VID_PLL_DIV_2: |
145 | shift_val = 0x0aaa; |
146 | shift_sel = 0; |
147 | break; |
148 | case VID_PLL_DIV_2p5: |
149 | shift_val = 0x5294; |
150 | shift_sel = 2; |
151 | break; |
152 | case VID_PLL_DIV_3: |
153 | shift_val = 0x0db6; |
154 | shift_sel = 0; |
155 | break; |
156 | case VID_PLL_DIV_3p5: |
157 | shift_val = 0x36cc; |
158 | shift_sel = 1; |
159 | break; |
160 | case VID_PLL_DIV_3p75: |
161 | shift_val = 0x6666; |
162 | shift_sel = 2; |
163 | break; |
164 | case VID_PLL_DIV_4: |
165 | shift_val = 0x0ccc; |
166 | shift_sel = 0; |
167 | break; |
168 | case VID_PLL_DIV_5: |
169 | shift_val = 0x739c; |
170 | shift_sel = 2; |
171 | break; |
172 | case VID_PLL_DIV_6: |
173 | shift_val = 0x0e38; |
174 | shift_sel = 0; |
175 | break; |
176 | case VID_PLL_DIV_6p25: |
177 | shift_val = 0x0000; |
178 | shift_sel = 3; |
179 | break; |
180 | case VID_PLL_DIV_7: |
181 | shift_val = 0x3c78; |
182 | shift_sel = 1; |
183 | break; |
184 | case VID_PLL_DIV_7p5: |
185 | shift_val = 0x78f0; |
186 | shift_sel = 2; |
187 | break; |
188 | case VID_PLL_DIV_12: |
189 | shift_val = 0x0fc0; |
190 | shift_sel = 0; |
191 | break; |
192 | case VID_PLL_DIV_14: |
193 | shift_val = 0x3f80; |
194 | shift_sel = 1; |
195 | break; |
196 | case VID_PLL_DIV_15: |
197 | shift_val = 0x7f80; |
198 | shift_sel = 2; |
199 | break; |
200 | } |
201 | |
202 | if (div == VID_PLL_DIV_1) |
203 | /* Enable vid_pll bypass to HDMI pll */ |
204 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
205 | VID_PLL_BYPASS, VID_PLL_BYPASS); |
206 | else { |
207 | /* Disable Bypass */ |
208 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
209 | VID_PLL_BYPASS, val: 0); |
210 | /* Clear sel */ |
211 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
212 | mask: 3 << 16, val: 0); |
213 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
214 | VID_PLL_PRESET, val: 0); |
215 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
216 | mask: 0x7fff, val: 0); |
217 | |
218 | /* Setup sel and val */ |
219 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
220 | mask: 3 << 16, val: shift_sel << 16); |
221 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
222 | VID_PLL_PRESET, VID_PLL_PRESET); |
223 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
224 | mask: 0x7fff, val: shift_val); |
225 | |
226 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
227 | VID_PLL_PRESET, val: 0); |
228 | } |
229 | |
230 | /* Enable the vid_pll output clock */ |
231 | regmap_update_bits(map: priv->hhi, HHI_VID_PLL_CLK_DIV, |
232 | VID_PLL_EN, VID_PLL_EN); |
233 | } |
234 | |
235 | /* |
236 | * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC |
237 | * |
238 | * TOFIX: Refactor into table to also handle HDMI frequency and paths |
239 | */ |
240 | static void meson_venci_cvbs_clock_config(struct meson_drm *priv) |
241 | { |
242 | unsigned int val; |
243 | |
244 | /* Setup PLL to output 1.485GHz */ |
245 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) { |
246 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x5800023d); |
247 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, val: 0x00404e00); |
248 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL3, val: 0x0d5c5091); |
249 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, val: 0x801da72c); |
250 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, val: 0x71486980); |
251 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x00000e55); |
252 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x4800023d); |
253 | |
254 | /* Poll for lock bit */ |
255 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, |
256 | (val & HDMI_PLL_LOCK), 10, 0); |
257 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
258 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) { |
259 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x4000027b); |
260 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, val: 0x800cb300); |
261 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL3, val: 0xa6212844); |
262 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, val: 0x0c4d000c); |
263 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, val: 0x001fa729); |
264 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x01a31500); |
265 | |
266 | /* Reset PLL */ |
267 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
268 | HDMI_PLL_RESET, HDMI_PLL_RESET); |
269 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
270 | HDMI_PLL_RESET, val: 0); |
271 | |
272 | /* Poll for lock bit */ |
273 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, |
274 | (val & HDMI_PLL_LOCK), 10, 0); |
275 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
276 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x1a0504f7); |
277 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, val: 0x00010000); |
278 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL3, val: 0x00000000); |
279 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, val: 0x6a28dc00); |
280 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, val: 0x65771290); |
281 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x39272000); |
282 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL7, val: 0x56540000); |
283 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x3a0504f7); |
284 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x1a0504f7); |
285 | |
286 | /* Poll for lock bit */ |
287 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, |
288 | ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A), |
289 | 10, 0); |
290 | } |
291 | |
292 | /* Disable VCLK2 */ |
293 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, val: 0); |
294 | |
295 | /* Setup vid_pll to /1 */ |
296 | meson_vid_pll_set(priv, div: VID_PLL_DIV_1); |
297 | |
298 | /* Setup the VCLK2 divider value to achieve 27MHz */ |
299 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_DIV, |
300 | VCLK2_DIV_MASK, val: (55 - 1)); |
301 | |
302 | /* select vid_pll for vclk2 */ |
303 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) |
304 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, |
305 | VCLK2_SEL_MASK, val: (0 << VCLK2_SEL_SHIFT)); |
306 | else |
307 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, |
308 | VCLK2_SEL_MASK, val: (4 << VCLK2_SEL_SHIFT)); |
309 | |
310 | /* enable vclk2 gate */ |
311 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); |
312 | |
313 | /* select vclk_div1 for enci */ |
314 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
315 | CTS_ENCI_SEL_MASK, val: (8 << CTS_ENCI_SEL_SHIFT)); |
316 | /* select vclk_div1 for vdac */ |
317 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_DIV, |
318 | CTS_VDAC_SEL_MASK, val: (8 << CTS_VDAC_SEL_SHIFT)); |
319 | |
320 | /* release vclk2_div_reset and enable vclk2_div */ |
321 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_DIV, |
322 | VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN); |
323 | |
324 | /* enable vclk2_div1 gate */ |
325 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, |
326 | VCLK2_DIV1_EN, VCLK2_DIV1_EN); |
327 | |
328 | /* reset vclk2 */ |
329 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, |
330 | VCLK2_SOFT_RESET, VCLK2_SOFT_RESET); |
331 | regmap_update_bits(map: priv->hhi, HHI_VIID_CLK_CNTL, |
332 | VCLK2_SOFT_RESET, val: 0); |
333 | |
334 | /* enable enci_clk */ |
335 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL2, |
336 | CTS_ENCI_EN, CTS_ENCI_EN); |
337 | /* enable vdac_clk */ |
338 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL2, |
339 | CTS_VDAC_EN, CTS_VDAC_EN); |
340 | } |
341 | |
342 | enum { |
343 | /* PLL O1 O2 O3 VP DV EN TX */ |
344 | /* 4320 /4 /4 /1 /5 /1 => /2 /2 */ |
345 | MESON_VCLK_HDMI_ENCI_54000 = 0, |
346 | /* 4320 /4 /4 /1 /5 /1 => /1 /2 */ |
347 | MESON_VCLK_HDMI_DDR_54000, |
348 | /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ |
349 | MESON_VCLK_HDMI_DDR_148500, |
350 | /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ |
351 | MESON_VCLK_HDMI_74250, |
352 | /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ |
353 | MESON_VCLK_HDMI_148500, |
354 | /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ |
355 | MESON_VCLK_HDMI_297000, |
356 | /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ |
357 | MESON_VCLK_HDMI_594000, |
358 | /* 2970 /1 /1 /1 /5 /1 => /1 /2 */ |
359 | MESON_VCLK_HDMI_594000_YUV420, |
360 | }; |
361 | |
362 | struct meson_vclk_params { |
363 | unsigned int pll_freq; |
364 | unsigned int phy_freq; |
365 | unsigned int vclk_freq; |
366 | unsigned int venc_freq; |
367 | unsigned int pixel_freq; |
368 | unsigned int pll_od1; |
369 | unsigned int pll_od2; |
370 | unsigned int pll_od3; |
371 | unsigned int vid_pll_div; |
372 | unsigned int vclk_div; |
373 | } params[] = { |
374 | [MESON_VCLK_HDMI_ENCI_54000] = { |
375 | .pll_freq = 4320000, |
376 | .phy_freq = 270000, |
377 | .vclk_freq = 54000, |
378 | .venc_freq = 54000, |
379 | .pixel_freq = 54000, |
380 | .pll_od1 = 4, |
381 | .pll_od2 = 4, |
382 | .pll_od3 = 1, |
383 | .vid_pll_div = VID_PLL_DIV_5, |
384 | .vclk_div = 1, |
385 | }, |
386 | [MESON_VCLK_HDMI_DDR_54000] = { |
387 | .pll_freq = 4320000, |
388 | .phy_freq = 270000, |
389 | .vclk_freq = 54000, |
390 | .venc_freq = 54000, |
391 | .pixel_freq = 27000, |
392 | .pll_od1 = 4, |
393 | .pll_od2 = 4, |
394 | .pll_od3 = 1, |
395 | .vid_pll_div = VID_PLL_DIV_5, |
396 | .vclk_div = 1, |
397 | }, |
398 | [MESON_VCLK_HDMI_DDR_148500] = { |
399 | .pll_freq = 2970000, |
400 | .phy_freq = 742500, |
401 | .vclk_freq = 148500, |
402 | .venc_freq = 148500, |
403 | .pixel_freq = 74250, |
404 | .pll_od1 = 4, |
405 | .pll_od2 = 1, |
406 | .pll_od3 = 1, |
407 | .vid_pll_div = VID_PLL_DIV_5, |
408 | .vclk_div = 1, |
409 | }, |
410 | [MESON_VCLK_HDMI_74250] = { |
411 | .pll_freq = 2970000, |
412 | .phy_freq = 742500, |
413 | .vclk_freq = 74250, |
414 | .venc_freq = 74250, |
415 | .pixel_freq = 74250, |
416 | .pll_od1 = 2, |
417 | .pll_od2 = 2, |
418 | .pll_od3 = 2, |
419 | .vid_pll_div = VID_PLL_DIV_5, |
420 | .vclk_div = 1, |
421 | }, |
422 | [MESON_VCLK_HDMI_148500] = { |
423 | .pll_freq = 2970000, |
424 | .phy_freq = 1485000, |
425 | .vclk_freq = 148500, |
426 | .venc_freq = 148500, |
427 | .pixel_freq = 148500, |
428 | .pll_od1 = 1, |
429 | .pll_od2 = 2, |
430 | .pll_od3 = 2, |
431 | .vid_pll_div = VID_PLL_DIV_5, |
432 | .vclk_div = 1, |
433 | }, |
434 | [MESON_VCLK_HDMI_297000] = { |
435 | .pll_freq = 5940000, |
436 | .phy_freq = 2970000, |
437 | .venc_freq = 297000, |
438 | .vclk_freq = 297000, |
439 | .pixel_freq = 297000, |
440 | .pll_od1 = 2, |
441 | .pll_od2 = 1, |
442 | .pll_od3 = 1, |
443 | .vid_pll_div = VID_PLL_DIV_5, |
444 | .vclk_div = 2, |
445 | }, |
446 | [MESON_VCLK_HDMI_594000] = { |
447 | .pll_freq = 5940000, |
448 | .phy_freq = 5940000, |
449 | .venc_freq = 594000, |
450 | .vclk_freq = 594000, |
451 | .pixel_freq = 594000, |
452 | .pll_od1 = 1, |
453 | .pll_od2 = 1, |
454 | .pll_od3 = 2, |
455 | .vid_pll_div = VID_PLL_DIV_5, |
456 | .vclk_div = 1, |
457 | }, |
458 | [MESON_VCLK_HDMI_594000_YUV420] = { |
459 | .pll_freq = 5940000, |
460 | .phy_freq = 2970000, |
461 | .venc_freq = 594000, |
462 | .vclk_freq = 594000, |
463 | .pixel_freq = 297000, |
464 | .pll_od1 = 2, |
465 | .pll_od2 = 1, |
466 | .pll_od3 = 1, |
467 | .vid_pll_div = VID_PLL_DIV_5, |
468 | .vclk_div = 1, |
469 | }, |
470 | { /* sentinel */ }, |
471 | }; |
472 | |
473 | static inline unsigned int pll_od_to_reg(unsigned int od) |
474 | { |
475 | switch (od) { |
476 | case 1: |
477 | return 0; |
478 | case 2: |
479 | return 1; |
480 | case 4: |
481 | return 2; |
482 | case 8: |
483 | return 3; |
484 | } |
485 | |
486 | /* Invalid */ |
487 | return 0; |
488 | } |
489 | |
490 | static void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, |
491 | unsigned int frac, unsigned int od1, |
492 | unsigned int od2, unsigned int od3) |
493 | { |
494 | unsigned int val; |
495 | |
496 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) { |
497 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x58000200 | m); |
498 | if (frac) |
499 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, |
500 | val: 0x00004000 | frac); |
501 | else |
502 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, |
503 | val: 0x00000000); |
504 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL3, val: 0x0d5c5091); |
505 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, val: 0x801da72c); |
506 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, val: 0x71486980); |
507 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x00000e55); |
508 | |
509 | /* Enable and unreset */ |
510 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
511 | mask: 0x7 << 28, HHI_HDMI_PLL_CNTL_EN); |
512 | |
513 | /* Poll for lock bit */ |
514 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, |
515 | val, (val & HDMI_PLL_LOCK), 10, 0); |
516 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
517 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) { |
518 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x40000200 | m); |
519 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, val: 0x800cb000 | frac); |
520 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL3, val: 0x860f30c4); |
521 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, val: 0x0c8e0000); |
522 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, val: 0x001fa729); |
523 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x01a31500); |
524 | |
525 | /* Reset PLL */ |
526 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
527 | HDMI_PLL_RESET, HDMI_PLL_RESET); |
528 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
529 | HDMI_PLL_RESET, val: 0); |
530 | |
531 | /* Poll for lock bit */ |
532 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, |
533 | (val & HDMI_PLL_LOCK), 10, 0); |
534 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
535 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL, val: 0x0b3a0400 | m); |
536 | |
537 | /* Enable and reset */ |
538 | /* TODO: add specific macro for g12a here */ |
539 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
540 | mask: 0x3 << 28, val: 0x3 << 28); |
541 | |
542 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL2, val: frac); |
543 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL3, val: 0x00000000); |
544 | |
545 | /* G12A HDMI PLL Needs specific parameters for 5.4GHz */ |
546 | if (m >= 0xf7) { |
547 | if (frac < 0x10000) { |
548 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, |
549 | val: 0x6a685c00); |
550 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, |
551 | val: 0x11551293); |
552 | } else { |
553 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, |
554 | val: 0xea68dc00); |
555 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, |
556 | val: 0x65771290); |
557 | } |
558 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x39272000); |
559 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL7, val: 0x55540000); |
560 | } else { |
561 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL4, val: 0x0a691c00); |
562 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL5, val: 0x33771290); |
563 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL6, val: 0x39270000); |
564 | regmap_write(map: priv->hhi, HHI_HDMI_PLL_CNTL7, val: 0x50540000); |
565 | } |
566 | |
567 | do { |
568 | /* Reset PLL */ |
569 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
570 | HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A); |
571 | |
572 | /* UN-Reset PLL */ |
573 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
574 | HDMI_PLL_RESET_G12A, val: 0); |
575 | |
576 | /* Poll for lock bits */ |
577 | if (!regmap_read_poll_timeout(priv->hhi, |
578 | HHI_HDMI_PLL_CNTL, val, |
579 | ((val & HDMI_PLL_LOCK_G12A) |
580 | == HDMI_PLL_LOCK_G12A), |
581 | 10, 100)) |
582 | break; |
583 | } while(1); |
584 | } |
585 | |
586 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) |
587 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL2, |
588 | mask: 3 << 16, val: pll_od_to_reg(od: od1) << 16); |
589 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
590 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) |
591 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL3, |
592 | mask: 3 << 21, val: pll_od_to_reg(od: od1) << 21); |
593 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) |
594 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
595 | mask: 3 << 16, val: pll_od_to_reg(od: od1) << 16); |
596 | |
597 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) |
598 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL2, |
599 | mask: 3 << 22, val: pll_od_to_reg(od: od2) << 22); |
600 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
601 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) |
602 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL3, |
603 | mask: 3 << 23, val: pll_od_to_reg(od: od2) << 23); |
604 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) |
605 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
606 | mask: 3 << 18, val: pll_od_to_reg(od: od2) << 18); |
607 | |
608 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) |
609 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL2, |
610 | mask: 3 << 18, val: pll_od_to_reg(od: od3) << 18); |
611 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
612 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) |
613 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL3, |
614 | mask: 3 << 19, val: pll_od_to_reg(od: od3) << 19); |
615 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) |
616 | regmap_update_bits(map: priv->hhi, HHI_HDMI_PLL_CNTL, |
617 | mask: 3 << 20, val: pll_od_to_reg(od: od3) << 20); |
618 | } |
619 | |
620 | #define XTAL_FREQ 24000 |
621 | |
622 | static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, |
623 | unsigned int pll_freq) |
624 | { |
625 | /* The GXBB PLL has a /2 pre-multiplier */ |
626 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) |
627 | pll_freq /= 2; |
628 | |
629 | return pll_freq / XTAL_FREQ; |
630 | } |
631 | |
632 | #define HDMI_FRAC_MAX_GXBB 4096 |
633 | #define HDMI_FRAC_MAX_GXL 1024 |
634 | #define HDMI_FRAC_MAX_G12A 131072 |
635 | |
636 | static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, |
637 | unsigned int m, |
638 | unsigned int pll_freq) |
639 | { |
640 | unsigned int parent_freq = XTAL_FREQ; |
641 | unsigned int frac_max = HDMI_FRAC_MAX_GXL; |
642 | unsigned int frac_m; |
643 | unsigned int frac; |
644 | |
645 | /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */ |
646 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) { |
647 | frac_max = HDMI_FRAC_MAX_GXBB; |
648 | parent_freq *= 2; |
649 | } |
650 | |
651 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) |
652 | frac_max = HDMI_FRAC_MAX_G12A; |
653 | |
654 | /* We can have a perfect match !*/ |
655 | if (pll_freq / m == parent_freq && |
656 | pll_freq % m == 0) |
657 | return 0; |
658 | |
659 | frac = div_u64(dividend: (u64)pll_freq * (u64)frac_max, divisor: parent_freq); |
660 | frac_m = m * frac_max; |
661 | if (frac_m > frac) |
662 | return frac_max; |
663 | frac -= frac_m; |
664 | |
665 | return min((u16)frac, (u16)(frac_max - 1)); |
666 | } |
667 | |
668 | static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, |
669 | unsigned int m, |
670 | unsigned int frac) |
671 | { |
672 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) { |
673 | /* Empiric supported min/max dividers */ |
674 | if (m < 53 || m > 123) |
675 | return false; |
676 | if (frac >= HDMI_FRAC_MAX_GXBB) |
677 | return false; |
678 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
679 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) { |
680 | /* Empiric supported min/max dividers */ |
681 | if (m < 106 || m > 247) |
682 | return false; |
683 | if (frac >= HDMI_FRAC_MAX_GXL) |
684 | return false; |
685 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
686 | /* Empiric supported min/max dividers */ |
687 | if (m < 106 || m > 247) |
688 | return false; |
689 | if (frac >= HDMI_FRAC_MAX_G12A) |
690 | return false; |
691 | } |
692 | |
693 | return true; |
694 | } |
695 | |
696 | static bool meson_hdmi_pll_find_params(struct meson_drm *priv, |
697 | unsigned int freq, |
698 | unsigned int *m, |
699 | unsigned int *frac, |
700 | unsigned int *od) |
701 | { |
702 | /* Cycle from /16 to /2 */ |
703 | for (*od = 16 ; *od > 1 ; *od >>= 1) { |
704 | *m = meson_hdmi_pll_get_m(priv, pll_freq: freq * *od); |
705 | if (!*m) |
706 | continue; |
707 | *frac = meson_hdmi_pll_get_frac(priv, m: *m, pll_freq: freq * *od); |
708 | |
709 | DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d\n" , |
710 | freq, *m, *frac, *od); |
711 | |
712 | if (meson_hdmi_pll_validate_params(priv, m: *m, frac: *frac)) |
713 | return true; |
714 | } |
715 | |
716 | return false; |
717 | } |
718 | |
719 | /* pll_freq is the frequency after the OD dividers */ |
720 | enum drm_mode_status |
721 | meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq) |
722 | { |
723 | unsigned int od, m, frac; |
724 | |
725 | /* In DMT mode, path after PLL is always /10 */ |
726 | freq *= 10; |
727 | |
728 | /* Check against soc revision/package limits */ |
729 | if (priv->limits) { |
730 | if (priv->limits->max_hdmi_phy_freq && |
731 | freq > priv->limits->max_hdmi_phy_freq) |
732 | return MODE_CLOCK_HIGH; |
733 | } |
734 | |
735 | if (meson_hdmi_pll_find_params(priv, freq, m: &m, frac: &frac, od: &od)) |
736 | return MODE_OK; |
737 | |
738 | return MODE_CLOCK_RANGE; |
739 | } |
740 | EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq); |
741 | |
742 | /* pll_freq is the frequency after the OD dividers */ |
743 | static void meson_hdmi_pll_generic_set(struct meson_drm *priv, |
744 | unsigned int pll_freq) |
745 | { |
746 | unsigned int od, m, frac, od1, od2, od3; |
747 | |
748 | if (meson_hdmi_pll_find_params(priv, freq: pll_freq, m: &m, frac: &frac, od: &od)) { |
749 | /* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */ |
750 | od3 = 1; |
751 | if (od < 4) { |
752 | od1 = 2; |
753 | od2 = 1; |
754 | } else { |
755 | od2 = od / 4; |
756 | od1 = od / od2; |
757 | } |
758 | |
759 | DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n" , |
760 | pll_freq, m, frac, od1, od2, od3); |
761 | |
762 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); |
763 | |
764 | return; |
765 | } |
766 | |
767 | DRM_ERROR("Fatal, unable to find parameters for PLL freq %d\n" , |
768 | pll_freq); |
769 | } |
770 | |
771 | enum drm_mode_status |
772 | meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, |
773 | unsigned int vclk_freq) |
774 | { |
775 | int i; |
776 | |
777 | DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n" , |
778 | phy_freq, vclk_freq); |
779 | |
780 | /* Check against soc revision/package limits */ |
781 | if (priv->limits) { |
782 | if (priv->limits->max_hdmi_phy_freq && |
783 | phy_freq > priv->limits->max_hdmi_phy_freq) |
784 | return MODE_CLOCK_HIGH; |
785 | } |
786 | |
787 | for (i = 0 ; params[i].pixel_freq ; ++i) { |
788 | DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n" , |
789 | i, params[i].pixel_freq, |
790 | FREQ_1000_1001(params[i].pixel_freq)); |
791 | DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n" , |
792 | i, params[i].phy_freq, |
793 | FREQ_1000_1001(params[i].phy_freq/10)*10); |
794 | /* Match strict frequency */ |
795 | if (phy_freq == params[i].phy_freq && |
796 | vclk_freq == params[i].vclk_freq) |
797 | return MODE_OK; |
798 | /* Match 1000/1001 variant */ |
799 | if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && |
800 | vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) |
801 | return MODE_OK; |
802 | } |
803 | |
804 | return MODE_CLOCK_RANGE; |
805 | } |
806 | EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq); |
807 | |
808 | static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, |
809 | unsigned int od1, unsigned int od2, unsigned int od3, |
810 | unsigned int vid_pll_div, unsigned int vclk_div, |
811 | unsigned int hdmi_tx_div, unsigned int venc_div, |
812 | bool hdmi_use_enci, bool vic_alternate_clock) |
813 | { |
814 | unsigned int m = 0, frac = 0; |
815 | |
816 | /* Set HDMI-TX sys clock */ |
817 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
818 | CTS_HDMI_SYS_SEL_MASK, val: 0); |
819 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
820 | CTS_HDMI_SYS_DIV_MASK, val: 0); |
821 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
822 | CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); |
823 | |
824 | /* Set HDMI PLL rate */ |
825 | if (!od1 && !od2 && !od3) { |
826 | meson_hdmi_pll_generic_set(priv, pll_freq: pll_base_freq); |
827 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXBB)) { |
828 | switch (pll_base_freq) { |
829 | case 2970000: |
830 | m = 0x3d; |
831 | frac = vic_alternate_clock ? 0xd02 : 0xe00; |
832 | break; |
833 | case 4320000: |
834 | m = vic_alternate_clock ? 0x59 : 0x5a; |
835 | frac = vic_alternate_clock ? 0xe8f : 0; |
836 | break; |
837 | case 5940000: |
838 | m = 0x7b; |
839 | frac = vic_alternate_clock ? 0xa05 : 0xc00; |
840 | break; |
841 | } |
842 | |
843 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); |
844 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
845 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) { |
846 | switch (pll_base_freq) { |
847 | case 2970000: |
848 | m = 0x7b; |
849 | frac = vic_alternate_clock ? 0x281 : 0x300; |
850 | break; |
851 | case 4320000: |
852 | m = vic_alternate_clock ? 0xb3 : 0xb4; |
853 | frac = vic_alternate_clock ? 0x347 : 0; |
854 | break; |
855 | case 5940000: |
856 | m = 0xf7; |
857 | frac = vic_alternate_clock ? 0x102 : 0x200; |
858 | break; |
859 | } |
860 | |
861 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); |
862 | } else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
863 | switch (pll_base_freq) { |
864 | case 2970000: |
865 | m = 0x7b; |
866 | frac = vic_alternate_clock ? 0x140b4 : 0x18000; |
867 | break; |
868 | case 4320000: |
869 | m = vic_alternate_clock ? 0xb3 : 0xb4; |
870 | frac = vic_alternate_clock ? 0x1a3ee : 0; |
871 | break; |
872 | case 5940000: |
873 | m = 0xf7; |
874 | frac = vic_alternate_clock ? 0x8148 : 0x10000; |
875 | break; |
876 | } |
877 | |
878 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); |
879 | } |
880 | |
881 | /* Setup vid_pll divider */ |
882 | meson_vid_pll_set(priv, div: vid_pll_div); |
883 | |
884 | /* Set VCLK div */ |
885 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
886 | VCLK_SEL_MASK, val: 0); |
887 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
888 | VCLK_DIV_MASK, val: vclk_div - 1); |
889 | |
890 | /* Set HDMI-TX source */ |
891 | switch (hdmi_tx_div) { |
892 | case 1: |
893 | /* enable vclk_div1 gate */ |
894 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
895 | VCLK_DIV1_EN, VCLK_DIV1_EN); |
896 | |
897 | /* select vclk_div1 for HDMI-TX */ |
898 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
899 | HDMI_TX_PIXEL_SEL_MASK, val: 0); |
900 | break; |
901 | case 2: |
902 | /* enable vclk_div2 gate */ |
903 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
904 | VCLK_DIV2_EN, VCLK_DIV2_EN); |
905 | |
906 | /* select vclk_div2 for HDMI-TX */ |
907 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
908 | HDMI_TX_PIXEL_SEL_MASK, val: 1 << HDMI_TX_PIXEL_SEL_SHIFT); |
909 | break; |
910 | case 4: |
911 | /* enable vclk_div4 gate */ |
912 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
913 | VCLK_DIV4_EN, VCLK_DIV4_EN); |
914 | |
915 | /* select vclk_div4 for HDMI-TX */ |
916 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
917 | HDMI_TX_PIXEL_SEL_MASK, val: 2 << HDMI_TX_PIXEL_SEL_SHIFT); |
918 | break; |
919 | case 6: |
920 | /* enable vclk_div6 gate */ |
921 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
922 | VCLK_DIV6_EN, VCLK_DIV6_EN); |
923 | |
924 | /* select vclk_div6 for HDMI-TX */ |
925 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
926 | HDMI_TX_PIXEL_SEL_MASK, val: 3 << HDMI_TX_PIXEL_SEL_SHIFT); |
927 | break; |
928 | case 12: |
929 | /* enable vclk_div12 gate */ |
930 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
931 | VCLK_DIV12_EN, VCLK_DIV12_EN); |
932 | |
933 | /* select vclk_div12 for HDMI-TX */ |
934 | regmap_update_bits(map: priv->hhi, HHI_HDMI_CLK_CNTL, |
935 | HDMI_TX_PIXEL_SEL_MASK, val: 4 << HDMI_TX_PIXEL_SEL_SHIFT); |
936 | break; |
937 | } |
938 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL2, |
939 | HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN); |
940 | |
941 | /* Set ENCI/ENCP Source */ |
942 | switch (venc_div) { |
943 | case 1: |
944 | /* enable vclk_div1 gate */ |
945 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
946 | VCLK_DIV1_EN, VCLK_DIV1_EN); |
947 | |
948 | if (hdmi_use_enci) |
949 | /* select vclk_div1 for enci */ |
950 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
951 | CTS_ENCI_SEL_MASK, val: 0); |
952 | else |
953 | /* select vclk_div1 for encp */ |
954 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
955 | CTS_ENCP_SEL_MASK, val: 0); |
956 | break; |
957 | case 2: |
958 | /* enable vclk_div2 gate */ |
959 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
960 | VCLK_DIV2_EN, VCLK_DIV2_EN); |
961 | |
962 | if (hdmi_use_enci) |
963 | /* select vclk_div2 for enci */ |
964 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
965 | CTS_ENCI_SEL_MASK, val: 1 << CTS_ENCI_SEL_SHIFT); |
966 | else |
967 | /* select vclk_div2 for encp */ |
968 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
969 | CTS_ENCP_SEL_MASK, val: 1 << CTS_ENCP_SEL_SHIFT); |
970 | break; |
971 | case 4: |
972 | /* enable vclk_div4 gate */ |
973 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
974 | VCLK_DIV4_EN, VCLK_DIV4_EN); |
975 | |
976 | if (hdmi_use_enci) |
977 | /* select vclk_div4 for enci */ |
978 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
979 | CTS_ENCI_SEL_MASK, val: 2 << CTS_ENCI_SEL_SHIFT); |
980 | else |
981 | /* select vclk_div4 for encp */ |
982 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
983 | CTS_ENCP_SEL_MASK, val: 2 << CTS_ENCP_SEL_SHIFT); |
984 | break; |
985 | case 6: |
986 | /* enable vclk_div6 gate */ |
987 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
988 | VCLK_DIV6_EN, VCLK_DIV6_EN); |
989 | |
990 | if (hdmi_use_enci) |
991 | /* select vclk_div6 for enci */ |
992 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
993 | CTS_ENCI_SEL_MASK, val: 3 << CTS_ENCI_SEL_SHIFT); |
994 | else |
995 | /* select vclk_div6 for encp */ |
996 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
997 | CTS_ENCP_SEL_MASK, val: 3 << CTS_ENCP_SEL_SHIFT); |
998 | break; |
999 | case 12: |
1000 | /* enable vclk_div12 gate */ |
1001 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, |
1002 | VCLK_DIV12_EN, VCLK_DIV12_EN); |
1003 | |
1004 | if (hdmi_use_enci) |
1005 | /* select vclk_div12 for enci */ |
1006 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
1007 | CTS_ENCI_SEL_MASK, val: 4 << CTS_ENCI_SEL_SHIFT); |
1008 | else |
1009 | /* select vclk_div12 for encp */ |
1010 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_DIV, |
1011 | CTS_ENCP_SEL_MASK, val: 4 << CTS_ENCP_SEL_SHIFT); |
1012 | break; |
1013 | } |
1014 | |
1015 | if (hdmi_use_enci) |
1016 | /* Enable ENCI clock gate */ |
1017 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL2, |
1018 | CTS_ENCI_EN, CTS_ENCI_EN); |
1019 | else |
1020 | /* Enable ENCP clock gate */ |
1021 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL2, |
1022 | CTS_ENCP_EN, CTS_ENCP_EN); |
1023 | |
1024 | regmap_update_bits(map: priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN); |
1025 | } |
1026 | |
1027 | void meson_vclk_setup(struct meson_drm *priv, unsigned int target, |
1028 | unsigned int phy_freq, unsigned int vclk_freq, |
1029 | unsigned int venc_freq, unsigned int dac_freq, |
1030 | bool hdmi_use_enci) |
1031 | { |
1032 | bool vic_alternate_clock = false; |
1033 | unsigned int freq; |
1034 | unsigned int hdmi_tx_div; |
1035 | unsigned int venc_div; |
1036 | |
1037 | if (target == MESON_VCLK_TARGET_CVBS) { |
1038 | meson_venci_cvbs_clock_config(priv); |
1039 | return; |
1040 | } else if (target == MESON_VCLK_TARGET_DMT) { |
1041 | /* |
1042 | * The DMT clock path is fixed after the PLL: |
1043 | * - automatic PLL freq + OD management |
1044 | * - vid_pll_div = VID_PLL_DIV_5 |
1045 | * - vclk_div = 2 |
1046 | * - hdmi_tx_div = 1 |
1047 | * - venc_div = 1 |
1048 | * - encp encoder |
1049 | */ |
1050 | meson_vclk_set(priv, pll_base_freq: phy_freq, od1: 0, od2: 0, od3: 0, |
1051 | vid_pll_div: VID_PLL_DIV_5, vclk_div: 2, hdmi_tx_div: 1, venc_div: 1, hdmi_use_enci: false, vic_alternate_clock: false); |
1052 | return; |
1053 | } |
1054 | |
1055 | hdmi_tx_div = vclk_freq / dac_freq; |
1056 | |
1057 | if (hdmi_tx_div == 0) { |
1058 | pr_err("Fatal Error, invalid HDMI-TX freq %d\n" , |
1059 | dac_freq); |
1060 | return; |
1061 | } |
1062 | |
1063 | venc_div = vclk_freq / venc_freq; |
1064 | |
1065 | if (venc_div == 0) { |
1066 | pr_err("Fatal Error, invalid HDMI venc freq %d\n" , |
1067 | venc_freq); |
1068 | return; |
1069 | } |
1070 | |
1071 | for (freq = 0 ; params[freq].pixel_freq ; ++freq) { |
1072 | if ((phy_freq == params[freq].phy_freq || |
1073 | phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && |
1074 | (vclk_freq == params[freq].vclk_freq || |
1075 | vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { |
1076 | if (vclk_freq != params[freq].vclk_freq) |
1077 | vic_alternate_clock = true; |
1078 | else |
1079 | vic_alternate_clock = false; |
1080 | |
1081 | if (freq == MESON_VCLK_HDMI_ENCI_54000 && |
1082 | !hdmi_use_enci) |
1083 | continue; |
1084 | |
1085 | if (freq == MESON_VCLK_HDMI_DDR_54000 && |
1086 | hdmi_use_enci) |
1087 | continue; |
1088 | |
1089 | if (freq == MESON_VCLK_HDMI_DDR_148500 && |
1090 | dac_freq == vclk_freq) |
1091 | continue; |
1092 | |
1093 | if (freq == MESON_VCLK_HDMI_148500 && |
1094 | dac_freq != vclk_freq) |
1095 | continue; |
1096 | break; |
1097 | } |
1098 | } |
1099 | |
1100 | if (!params[freq].pixel_freq) { |
1101 | pr_err("Fatal Error, invalid HDMI vclk freq %d\n" , vclk_freq); |
1102 | return; |
1103 | } |
1104 | |
1105 | meson_vclk_set(priv, pll_base_freq: params[freq].pll_freq, |
1106 | od1: params[freq].pll_od1, od2: params[freq].pll_od2, |
1107 | od3: params[freq].pll_od3, vid_pll_div: params[freq].vid_pll_div, |
1108 | vclk_div: params[freq].vclk_div, hdmi_tx_div, venc_div, |
1109 | hdmi_use_enci, vic_alternate_clock); |
1110 | } |
1111 | EXPORT_SYMBOL_GPL(meson_vclk_setup); |
1112 | |