blob: 693e0ebe398f4e3faddcacf7d7bd461ee5ab05fe [file] [log] [blame]
Neil Armstrong3bed4222018-07-24 17:45:28 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Amlogic Meson Video Processing Unit driver
4 *
5 * Copyright (c) 2018 BayLibre, SAS.
6 * Author: Neil Armstrong <narmstrong@baylibre.com>
7 */
8
9#include <edid.h>
10#include "meson_vpu.h"
11#include <linux/iopoll.h>
12#include <linux/math64.h>
13
14#define writel_bits(mask, val, addr) \
15 writel((readl(addr) & ~(mask)) | (val), addr)
16
17enum {
18 MESON_VCLK_TARGET_CVBS = 0,
19 MESON_VCLK_TARGET_HDMI = 1,
20 MESON_VCLK_TARGET_DMT = 2,
21};
22
23/* HHI Registers */
24#define HHI_VID_PLL_CLK_DIV 0x1a0 /* 0x68 offset in data sheet */
25#define VID_PLL_EN BIT(19)
26#define VID_PLL_BYPASS BIT(18)
27#define VID_PLL_PRESET BIT(15)
28#define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */
29#define VCLK2_DIV_MASK 0xff
30#define VCLK2_DIV_EN BIT(16)
31#define VCLK2_DIV_RESET BIT(17)
32#define CTS_VDAC_SEL_MASK (0xf << 28)
33#define CTS_VDAC_SEL_SHIFT 28
34#define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */
35#define VCLK2_EN BIT(19)
36#define VCLK2_SEL_MASK (0x7 << 16)
37#define VCLK2_SEL_SHIFT 16
38#define VCLK2_SOFT_RESET BIT(15)
39#define VCLK2_DIV1_EN BIT(0)
40#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */
41#define VCLK_DIV_MASK 0xff
42#define VCLK_DIV_EN BIT(16)
43#define VCLK_DIV_RESET BIT(17)
44#define CTS_ENCP_SEL_MASK (0xf << 24)
45#define CTS_ENCP_SEL_SHIFT 24
46#define CTS_ENCI_SEL_MASK (0xf << 28)
47#define CTS_ENCI_SEL_SHIFT 28
48#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */
49#define VCLK_EN BIT(19)
50#define VCLK_SEL_MASK (0x7 << 16)
51#define VCLK_SEL_SHIFT 16
52#define VCLK_SOFT_RESET BIT(15)
53#define VCLK_DIV1_EN BIT(0)
54#define VCLK_DIV2_EN BIT(1)
55#define VCLK_DIV4_EN BIT(2)
56#define VCLK_DIV6_EN BIT(3)
57#define VCLK_DIV12_EN BIT(4)
58#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */
59#define CTS_ENCI_EN BIT(0)
60#define CTS_ENCP_EN BIT(2)
61#define CTS_VDAC_EN BIT(4)
62#define HDMI_TX_PIXEL_EN BIT(5)
63#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */
64#define HDMI_TX_PIXEL_SEL_MASK (0xf << 16)
65#define HDMI_TX_PIXEL_SEL_SHIFT 16
66#define CTS_HDMI_SYS_SEL_MASK (0x7 << 9)
67#define CTS_HDMI_SYS_DIV_MASK (0x7f)
68#define CTS_HDMI_SYS_EN BIT(8)
69
70#define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
71#define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */
72#define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */
73#define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */
74#define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */
75#define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */
76
77#define HDMI_PLL_RESET BIT(28)
78#define HDMI_PLL_LOCK BIT(31)
79
80/* VID PLL Dividers */
81enum {
82 VID_PLL_DIV_1 = 0,
83 VID_PLL_DIV_2,
84 VID_PLL_DIV_2p5,
85 VID_PLL_DIV_3,
86 VID_PLL_DIV_3p5,
87 VID_PLL_DIV_3p75,
88 VID_PLL_DIV_4,
89 VID_PLL_DIV_5,
90 VID_PLL_DIV_6,
91 VID_PLL_DIV_6p25,
92 VID_PLL_DIV_7,
93 VID_PLL_DIV_7p5,
94 VID_PLL_DIV_12,
95 VID_PLL_DIV_14,
96 VID_PLL_DIV_15,
97};
98
99void meson_vid_pll_set(struct meson_vpu_priv *priv, unsigned int div)
100{
101 unsigned int shift_val = 0;
102 unsigned int shift_sel = 0;
103
104 /* Disable vid_pll output clock */
105 hhi_update_bits(HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
106 hhi_update_bits(HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
107
108 switch (div) {
109 case VID_PLL_DIV_2:
110 shift_val = 0x0aaa;
111 shift_sel = 0;
112 break;
113 case VID_PLL_DIV_2p5:
114 shift_val = 0x5294;
115 shift_sel = 2;
116 break;
117 case VID_PLL_DIV_3:
118 shift_val = 0x0db6;
119 shift_sel = 0;
120 break;
121 case VID_PLL_DIV_3p5:
122 shift_val = 0x36cc;
123 shift_sel = 1;
124 break;
125 case VID_PLL_DIV_3p75:
126 shift_val = 0x6666;
127 shift_sel = 2;
128 break;
129 case VID_PLL_DIV_4:
130 shift_val = 0x0ccc;
131 shift_sel = 0;
132 break;
133 case VID_PLL_DIV_5:
134 shift_val = 0x739c;
135 shift_sel = 2;
136 break;
137 case VID_PLL_DIV_6:
138 shift_val = 0x0e38;
139 shift_sel = 0;
140 break;
141 case VID_PLL_DIV_6p25:
142 shift_val = 0x0000;
143 shift_sel = 3;
144 break;
145 case VID_PLL_DIV_7:
146 shift_val = 0x3c78;
147 shift_sel = 1;
148 break;
149 case VID_PLL_DIV_7p5:
150 shift_val = 0x78f0;
151 shift_sel = 2;
152 break;
153 case VID_PLL_DIV_12:
154 shift_val = 0x0fc0;
155 shift_sel = 0;
156 break;
157 case VID_PLL_DIV_14:
158 shift_val = 0x3f80;
159 shift_sel = 1;
160 break;
161 case VID_PLL_DIV_15:
162 shift_val = 0x7f80;
163 shift_sel = 2;
164 break;
165 }
166
167 if (div == VID_PLL_DIV_1) {
168 /* Enable vid_pll bypass to HDMI pll */
169 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
170 VID_PLL_BYPASS, VID_PLL_BYPASS);
171 } else {
172 /* Disable Bypass */
173 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
174 VID_PLL_BYPASS, 0);
175 /* Clear sel */
176 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
177 3 << 16, 0);
178 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
179 VID_PLL_PRESET, 0);
180 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
181 0x7fff, 0);
182
183 /* Setup sel and val */
184 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
185 3 << 16, shift_sel << 16);
186 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
187 VID_PLL_PRESET, VID_PLL_PRESET);
188 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
189 0x7fff, shift_val);
190
191 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
192 VID_PLL_PRESET, 0);
193 }
194
195 /* Enable the vid_pll output clock */
196 hhi_update_bits(HHI_VID_PLL_CLK_DIV,
197 VID_PLL_EN, VID_PLL_EN);
198}
199
200/*
201 * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC
202 *
203 * TOFIX: Refactor into table to also handle HDMI frequency and paths
204 */
205static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
206{
207 unsigned int val;
208
209 debug("%s:%d\n", __func__, __LINE__);
210
211 /* Setup PLL to output 1.485GHz */
212 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
213 hhi_write(HHI_HDMI_PLL_CNTL, 0x5800023d);
214 hhi_write(HHI_HDMI_PLL_CNTL2, 0x00404e00);
215 hhi_write(HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
216 hhi_write(HHI_HDMI_PLL_CNTL4, 0x801da72c);
217 hhi_write(HHI_HDMI_PLL_CNTL5, 0x71486980);
218 hhi_write(HHI_HDMI_PLL_CNTL6, 0x00000e55);
219 hhi_write(HHI_HDMI_PLL_CNTL, 0x4800023d);
220 } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
221 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
222 hhi_write(HHI_HDMI_PLL_CNTL, 0x4000027b);
223 hhi_write(HHI_HDMI_PLL_CNTL2, 0x800cb300);
224 hhi_write(HHI_HDMI_PLL_CNTL3, 0xa6212844);
225 hhi_write(HHI_HDMI_PLL_CNTL4, 0x0c4d000c);
226 hhi_write(HHI_HDMI_PLL_CNTL5, 0x001fa729);
227 hhi_write(HHI_HDMI_PLL_CNTL6, 0x01a31500);
228
229 /* Reset PLL */
230 hhi_update_bits(HHI_HDMI_PLL_CNTL,
231 HDMI_PLL_RESET, HDMI_PLL_RESET);
232 hhi_update_bits(HHI_HDMI_PLL_CNTL,
233 HDMI_PLL_RESET, 0);
234 }
235
236 debug("%s:%d\n", __func__, __LINE__);
237
238 /* Poll for lock bit */
239 readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
240 (val & HDMI_PLL_LOCK), 10);
241
242 /* Disable VCLK2 */
243 hhi_update_bits(HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
244
245 /* Setup vid_pll to /1 */
246 meson_vid_pll_set(priv, VID_PLL_DIV_1);
247
248 /* Setup the VCLK2 divider value to achieve 27MHz */
249 hhi_update_bits(HHI_VIID_CLK_DIV,
250 VCLK2_DIV_MASK, (55 - 1));
251
252 /* select vid_pll for vclk2 */
253 hhi_update_bits(HHI_VIID_CLK_CNTL,
254 VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
255 /* enable vclk2 gate */
256 hhi_update_bits(HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
257
258 /* select vclk_div1 for enci */
259 hhi_update_bits(HHI_VID_CLK_DIV,
260 CTS_ENCI_SEL_MASK, (8 << CTS_ENCI_SEL_SHIFT));
261 /* select vclk_div1 for vdac */
262 hhi_update_bits(HHI_VIID_CLK_DIV,
263 CTS_VDAC_SEL_MASK, (8 << CTS_VDAC_SEL_SHIFT));
264
265 /* release vclk2_div_reset and enable vclk2_div */
266 hhi_update_bits(HHI_VIID_CLK_DIV,
267 VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN);
268
269 /* enable vclk2_div1 gate */
270 hhi_update_bits(HHI_VIID_CLK_CNTL,
271 VCLK2_DIV1_EN, VCLK2_DIV1_EN);
272
273 /* reset vclk2 */
274 hhi_update_bits(HHI_VIID_CLK_CNTL,
275 VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
276 hhi_update_bits(HHI_VIID_CLK_CNTL,
277 VCLK2_SOFT_RESET, 0);
278
279 /* enable enci_clk */
280 hhi_update_bits(HHI_VID_CLK_CNTL2,
281 CTS_ENCI_EN, CTS_ENCI_EN);
282 /* enable vdac_clk */
283 hhi_update_bits(HHI_VID_CLK_CNTL2,
284 CTS_VDAC_EN, CTS_VDAC_EN);
285
286 debug("%s:%d\n", __func__, __LINE__);
287}
288
289enum {
290/* PLL O1 O2 O3 VP DV EN TX */
291/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
292 MESON_VCLK_HDMI_ENCI_54000 = 1,
293/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
294 MESON_VCLK_HDMI_DDR_54000,
295/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
296 MESON_VCLK_HDMI_DDR_148500,
297/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
298 MESON_VCLK_HDMI_74250,
299/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
300 MESON_VCLK_HDMI_148500,
301/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
302 MESON_VCLK_HDMI_297000,
303/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
304 MESON_VCLK_HDMI_594000
305};
306
307struct meson_vclk_params {
308 unsigned int pll_base_freq;
309 unsigned int pll_od1;
310 unsigned int pll_od2;
311 unsigned int pll_od3;
312 unsigned int vid_pll_div;
313 unsigned int vclk_div;
314} params[] = {
315 [MESON_VCLK_HDMI_ENCI_54000] = {
316 .pll_base_freq = 4320000,
317 .pll_od1 = 4,
318 .pll_od2 = 4,
319 .pll_od3 = 1,
320 .vid_pll_div = VID_PLL_DIV_5,
321 .vclk_div = 1,
322 },
323 [MESON_VCLK_HDMI_DDR_54000] = {
324 .pll_base_freq = 4320000,
325 .pll_od1 = 4,
326 .pll_od2 = 4,
327 .pll_od3 = 1,
328 .vid_pll_div = VID_PLL_DIV_5,
329 .vclk_div = 1,
330 },
331 [MESON_VCLK_HDMI_DDR_148500] = {
332 .pll_base_freq = 2970000,
333 .pll_od1 = 4,
334 .pll_od2 = 1,
335 .pll_od3 = 1,
336 .vid_pll_div = VID_PLL_DIV_5,
337 .vclk_div = 1,
338 },
339 [MESON_VCLK_HDMI_74250] = {
340 .pll_base_freq = 2970000,
341 .pll_od1 = 2,
342 .pll_od2 = 2,
343 .pll_od3 = 2,
344 .vid_pll_div = VID_PLL_DIV_5,
345 .vclk_div = 1,
346 },
347 [MESON_VCLK_HDMI_148500] = {
348 .pll_base_freq = 2970000,
349 .pll_od1 = 1,
350 .pll_od2 = 2,
351 .pll_od3 = 2,
352 .vid_pll_div = VID_PLL_DIV_5,
353 .vclk_div = 1,
354 },
355 [MESON_VCLK_HDMI_297000] = {
356 .pll_base_freq = 2970000,
357 .pll_od1 = 1,
358 .pll_od2 = 1,
359 .pll_od3 = 1,
360 .vid_pll_div = VID_PLL_DIV_5,
361 .vclk_div = 2,
362 },
363 [MESON_VCLK_HDMI_594000] = {
364 .pll_base_freq = 5940000,
365 .pll_od1 = 1,
366 .pll_od2 = 1,
367 .pll_od3 = 2,
368 .vid_pll_div = VID_PLL_DIV_5,
369 .vclk_div = 1,
370 },
371};
372
373static inline unsigned int pll_od_to_reg(unsigned int od)
374{
375 switch (od) {
376 case 1:
377 return 0;
378 case 2:
379 return 1;
380 case 4:
381 return 2;
382 case 8:
383 return 3;
384 }
385
386 /* Invalid */
387 return 0;
388}
389
390void meson_hdmi_pll_set_params(struct meson_vpu_priv *priv, unsigned int m,
391 unsigned int frac, unsigned int od1,
392 unsigned int od2, unsigned int od3)
393{
394 unsigned int val;
395
396 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
397 hhi_write(HHI_HDMI_PLL_CNTL, 0x58000200 | m);
398 if (frac)
399 hhi_write(HHI_HDMI_PLL_CNTL2,
400 0x00004000 | frac);
401 else
402 hhi_write(HHI_HDMI_PLL_CNTL2,
403 0x00000000);
404 hhi_write(HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
405 hhi_write(HHI_HDMI_PLL_CNTL4, 0x801da72c);
406 hhi_write(HHI_HDMI_PLL_CNTL5, 0x71486980);
407 hhi_write(HHI_HDMI_PLL_CNTL6, 0x00000e55);
408
409 /* Enable and unreset */
410 hhi_update_bits(HHI_HDMI_PLL_CNTL,
411 0x7 << 28, 0x4 << 28);
412
413 /* Poll for lock bit */
414 readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
415 (val & HDMI_PLL_LOCK), 10);
416 } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
417 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
418 hhi_write(HHI_HDMI_PLL_CNTL, 0x40000200 | m);
419 hhi_write(HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
420 hhi_write(HHI_HDMI_PLL_CNTL3, 0x860f30c4);
421 hhi_write(HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
422 hhi_write(HHI_HDMI_PLL_CNTL5, 0x001fa729);
423 hhi_write(HHI_HDMI_PLL_CNTL6, 0x01a31500);
424
425 /* Reset PLL */
426 hhi_update_bits(HHI_HDMI_PLL_CNTL,
427 HDMI_PLL_RESET, HDMI_PLL_RESET);
428 hhi_update_bits(HHI_HDMI_PLL_CNTL,
429 HDMI_PLL_RESET, 0);
430
431 /* Poll for lock bit */
432 readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
433 (val & HDMI_PLL_LOCK), 10);
434 }
435
436 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
437 hhi_update_bits(HHI_HDMI_PLL_CNTL2,
438 3 << 16, pll_od_to_reg(od1) << 16);
439 else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
440 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
441 hhi_update_bits(HHI_HDMI_PLL_CNTL3,
442 3 << 21, pll_od_to_reg(od1) << 21);
443
444 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
445 hhi_update_bits(HHI_HDMI_PLL_CNTL2,
446 3 << 22, pll_od_to_reg(od2) << 22);
447 else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
448 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
449 hhi_update_bits(HHI_HDMI_PLL_CNTL3,
450 3 << 23, pll_od_to_reg(od2) << 23);
451
452 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
453 hhi_update_bits(HHI_HDMI_PLL_CNTL2,
454 3 << 18, pll_od_to_reg(od3) << 18);
455 else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
456 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
457 hhi_update_bits(HHI_HDMI_PLL_CNTL3,
458 3 << 19, pll_od_to_reg(od3) << 19);
459}
460
461#define XTAL_FREQ 24000
462
463static unsigned int meson_hdmi_pll_get_m(struct meson_vpu_priv *priv,
464 unsigned int pll_freq)
465{
466 /* The GXBB PLL has a /2 pre-multiplier */
467 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
468 pll_freq /= 2;
469
470 return pll_freq / XTAL_FREQ;
471}
472
473#define HDMI_FRAC_MAX_GXBB 4096
474#define HDMI_FRAC_MAX_GXL 1024
475
476static unsigned int meson_hdmi_pll_get_frac(struct meson_vpu_priv *priv,
477 unsigned int m,
478 unsigned int pll_freq)
479{
480 unsigned int parent_freq = XTAL_FREQ;
481 unsigned int frac_max = HDMI_FRAC_MAX_GXL;
482 unsigned int frac_m;
483 unsigned int frac;
484
485 /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */
486 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
487 frac_max = HDMI_FRAC_MAX_GXBB;
488 parent_freq *= 2;
489 }
490
491 /* We can have a perfect match !*/
492 if (pll_freq / m == parent_freq &&
493 pll_freq % m == 0)
494 return 0;
495
496 frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq);
497 frac_m = m * frac_max;
498 if (frac_m > frac)
499 return frac_max;
500 frac -= frac_m;
501
502 return min((u16)frac, (u16)(frac_max - 1));
503}
504
505static bool meson_hdmi_pll_validate_params(struct meson_vpu_priv *priv,
506 unsigned int m,
507 unsigned int frac)
508{
509 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
510 /* Empiric supported min/max dividers */
511 if (m < 53 || m > 123)
512 return false;
513 if (frac >= HDMI_FRAC_MAX_GXBB)
514 return false;
515 } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
516 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
517 /* Empiric supported min/max dividers */
518 if (m < 106 || m > 247)
519 return false;
520 if (frac >= HDMI_FRAC_MAX_GXL)
521 return false;
522 }
523
524 return true;
525}
526
527static bool meson_hdmi_pll_find_params(struct meson_vpu_priv *priv,
528 unsigned int freq,
529 unsigned int *m,
530 unsigned int *frac,
531 unsigned int *od)
532{
533 /* Cycle from /16 to /2 */
534 for (*od = 16 ; *od > 1 ; *od >>= 1) {
535 *m = meson_hdmi_pll_get_m(priv, freq * *od);
536 if (!*m)
537 continue;
538 *frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od);
539
540 debug("PLL params for %dkHz: m=%x frac=%x od=%d\n",
541 freq, *m, *frac, *od);
542
543 if (meson_hdmi_pll_validate_params(priv, *m, *frac))
544 return true;
545 }
546
547 return false;
548}
549
550/* pll_freq is the frequency after the OD dividers */
551bool meson_vclk_dmt_supported_freq(struct meson_vpu_priv *priv,
552 unsigned int freq)
553{
554 unsigned int od, m, frac;
555
556 /* In DMT mode, path after PLL is always /10 */
557 freq *= 10;
558
559 if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
560 return true;
561
562 return false;
563}
564
565/* pll_freq is the frequency after the OD dividers */
566static void meson_hdmi_pll_generic_set(struct meson_vpu_priv *priv,
567 unsigned int pll_freq)
568{
569 unsigned int od, m, frac, od1, od2, od3;
570
571 if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
572 od3 = 1;
573 if (od < 4) {
574 od1 = 2;
575 od2 = 1;
576 } else {
577 od2 = od / 4;
578 od1 = od / od2;
579 }
580
581 debug("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n",
582 pll_freq, m, frac, od1, od2, od3);
583
584 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
585
586 return;
587 }
588
589 printf("Fatal, unable to find parameters for PLL freq %d\n",
590 pll_freq);
591}
592
593static void
594meson_vclk_set(struct meson_vpu_priv *priv, unsigned int pll_base_freq,
595 unsigned int od1, unsigned int od2, unsigned int od3,
596 unsigned int vid_pll_div, unsigned int vclk_div,
597 unsigned int hdmi_tx_div, unsigned int venc_div,
598 bool hdmi_use_enci)
599{
600 /* Set HDMI-TX sys clock */
601 hhi_update_bits(HHI_HDMI_CLK_CNTL,
602 CTS_HDMI_SYS_SEL_MASK, 0);
603 hhi_update_bits(HHI_HDMI_CLK_CNTL,
604 CTS_HDMI_SYS_DIV_MASK, 0);
605 hhi_update_bits(HHI_HDMI_CLK_CNTL,
606 CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
607
608 /* Set HDMI PLL rate */
609 if (!od1 && !od2 && !od3) {
610 meson_hdmi_pll_generic_set(priv, pll_base_freq);
611 } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
612 switch (pll_base_freq) {
613 case 2970000:
614 meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
615 od1, od2, od3);
616 break;
617 case 4320000:
618 meson_hdmi_pll_set_params(priv, 0x5a, 0,
619 od1, od2, od3);
620 break;
621 case 5940000:
622 meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
623 od1, od2, od3);
624 break;
625 }
626 } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
627 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
628 switch (pll_base_freq) {
629 case 2970000:
630 meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
631 od1, od2, od3);
632 break;
633 case 4320000:
634 meson_hdmi_pll_set_params(priv, 0xb4, 0,
635 od1, od2, od3);
636 break;
637 case 5940000:
638 meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
639 od1, od2, od3);
640 break;
641 }
642 }
643
644 /* Setup vid_pll divider */
645 meson_vid_pll_set(priv, vid_pll_div);
646
647 /* Set VCLK div */
648 hhi_update_bits(HHI_VID_CLK_CNTL,
649 VCLK_SEL_MASK, 0);
650 hhi_update_bits(HHI_VID_CLK_DIV,
651 VCLK_DIV_MASK, vclk_div - 1);
652
653 /* Set HDMI-TX source */
654 switch (hdmi_tx_div) {
655 case 1:
656 /* enable vclk_div1 gate */
657 hhi_update_bits(HHI_VID_CLK_CNTL,
658 VCLK_DIV1_EN, VCLK_DIV1_EN);
659
660 /* select vclk_div1 for HDMI-TX */
661 hhi_update_bits(HHI_HDMI_CLK_CNTL,
662 HDMI_TX_PIXEL_SEL_MASK, 0);
663 break;
664 case 2:
665 /* enable vclk_div2 gate */
666 hhi_update_bits(HHI_VID_CLK_CNTL,
667 VCLK_DIV2_EN, VCLK_DIV2_EN);
668
669 /* select vclk_div2 for HDMI-TX */
670 hhi_update_bits(HHI_HDMI_CLK_CNTL,
671 HDMI_TX_PIXEL_SEL_MASK,
672 1 << HDMI_TX_PIXEL_SEL_SHIFT);
673 break;
674 case 4:
675 /* enable vclk_div4 gate */
676 hhi_update_bits(HHI_VID_CLK_CNTL,
677 VCLK_DIV4_EN, VCLK_DIV4_EN);
678
679 /* select vclk_div4 for HDMI-TX */
680 hhi_update_bits(HHI_HDMI_CLK_CNTL,
681 HDMI_TX_PIXEL_SEL_MASK,
682 2 << HDMI_TX_PIXEL_SEL_SHIFT);
683 break;
684 case 6:
685 /* enable vclk_div6 gate */
686 hhi_update_bits(HHI_VID_CLK_CNTL,
687 VCLK_DIV6_EN, VCLK_DIV6_EN);
688
689 /* select vclk_div6 for HDMI-TX */
690 hhi_update_bits(HHI_HDMI_CLK_CNTL,
691 HDMI_TX_PIXEL_SEL_MASK,
692 3 << HDMI_TX_PIXEL_SEL_SHIFT);
693 break;
694 case 12:
695 /* enable vclk_div12 gate */
696 hhi_update_bits(HHI_VID_CLK_CNTL,
697 VCLK_DIV12_EN, VCLK_DIV12_EN);
698
699 /* select vclk_div12 for HDMI-TX */
700 hhi_update_bits(HHI_HDMI_CLK_CNTL,
701 HDMI_TX_PIXEL_SEL_MASK,
702 4 << HDMI_TX_PIXEL_SEL_SHIFT);
703 break;
704 }
705 hhi_update_bits(HHI_VID_CLK_CNTL2,
706 HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
707
708 /* Set ENCI/ENCP Source */
709 switch (venc_div) {
710 case 1:
711 /* enable vclk_div1 gate */
712 hhi_update_bits(HHI_VID_CLK_CNTL,
713 VCLK_DIV1_EN, VCLK_DIV1_EN);
714
715 if (hdmi_use_enci)
716 /* select vclk_div1 for enci */
717 hhi_update_bits(HHI_VID_CLK_DIV,
718 CTS_ENCI_SEL_MASK, 0);
719 else
720 /* select vclk_div1 for encp */
721 hhi_update_bits(HHI_VID_CLK_DIV,
722 CTS_ENCP_SEL_MASK, 0);
723 break;
724 case 2:
725 /* enable vclk_div2 gate */
726 hhi_update_bits(HHI_VID_CLK_CNTL,
727 VCLK_DIV2_EN, VCLK_DIV2_EN);
728
729 if (hdmi_use_enci)
730 /* select vclk_div2 for enci */
731 hhi_update_bits(HHI_VID_CLK_DIV,
732 CTS_ENCI_SEL_MASK,
733 1 << CTS_ENCI_SEL_SHIFT);
734 else
735 /* select vclk_div2 for encp */
736 hhi_update_bits(HHI_VID_CLK_DIV,
737 CTS_ENCP_SEL_MASK,
738 1 << CTS_ENCP_SEL_SHIFT);
739 break;
740 case 4:
741 /* enable vclk_div4 gate */
742 hhi_update_bits(HHI_VID_CLK_CNTL,
743 VCLK_DIV4_EN, VCLK_DIV4_EN);
744
745 if (hdmi_use_enci)
746 /* select vclk_div4 for enci */
747 hhi_update_bits(HHI_VID_CLK_DIV,
748 CTS_ENCI_SEL_MASK,
749 2 << CTS_ENCI_SEL_SHIFT);
750 else
751 /* select vclk_div4 for encp */
752 hhi_update_bits(HHI_VID_CLK_DIV,
753 CTS_ENCP_SEL_MASK,
754 2 << CTS_ENCP_SEL_SHIFT);
755 break;
756 case 6:
757 /* enable vclk_div6 gate */
758 hhi_update_bits(HHI_VID_CLK_CNTL,
759 VCLK_DIV6_EN, VCLK_DIV6_EN);
760
761 if (hdmi_use_enci)
762 /* select vclk_div6 for enci */
763 hhi_update_bits(HHI_VID_CLK_DIV,
764 CTS_ENCI_SEL_MASK,
765 3 << CTS_ENCI_SEL_SHIFT);
766 else
767 /* select vclk_div6 for encp */
768 hhi_update_bits(HHI_VID_CLK_DIV,
769 CTS_ENCP_SEL_MASK,
770 3 << CTS_ENCP_SEL_SHIFT);
771 break;
772 case 12:
773 /* enable vclk_div12 gate */
774 hhi_update_bits(HHI_VID_CLK_CNTL,
775 VCLK_DIV12_EN, VCLK_DIV12_EN);
776
777 if (hdmi_use_enci)
778 /* select vclk_div12 for enci */
779 hhi_update_bits(HHI_VID_CLK_DIV,
780 CTS_ENCI_SEL_MASK,
781 4 << CTS_ENCI_SEL_SHIFT);
782 else
783 /* select vclk_div12 for encp */
784 hhi_update_bits(HHI_VID_CLK_DIV,
785 CTS_ENCP_SEL_MASK,
786 4 << CTS_ENCP_SEL_SHIFT);
787 break;
788 }
789
790 if (hdmi_use_enci)
791 /* Enable ENCI clock gate */
792 hhi_update_bits(HHI_VID_CLK_CNTL2,
793 CTS_ENCI_EN, CTS_ENCI_EN);
794 else
795 /* Enable ENCP clock gate */
796 hhi_update_bits(HHI_VID_CLK_CNTL2,
797 CTS_ENCP_EN, CTS_ENCP_EN);
798
799 hhi_update_bits(HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
800}
801
802static void meson_vclk_setup(struct meson_vpu_priv *priv, unsigned int target,
803 unsigned int vclk_freq, unsigned int venc_freq,
804 unsigned int dac_freq, bool hdmi_use_enci)
805{
806 unsigned int freq;
807 unsigned int hdmi_tx_div;
808 unsigned int venc_div;
809
810 if (target == MESON_VCLK_TARGET_CVBS) {
811 meson_venci_cvbs_clock_config(priv);
812 return;
813 } else if (target == MESON_VCLK_TARGET_DMT) {
814 /* The DMT clock path is fixed after the PLL:
815 * - automatic PLL freq + OD management
816 * - vid_pll_div = VID_PLL_DIV_5
817 * - vclk_div = 2
818 * - hdmi_tx_div = 1
819 * - venc_div = 1
820 * - encp encoder
821 */
822 meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
823 VID_PLL_DIV_5, 2, 1, 1, false);
824
825 return;
826 }
827
828 hdmi_tx_div = vclk_freq / dac_freq;
829
830 if (hdmi_tx_div == 0) {
831 printf("Fatal Error, invalid HDMI-TX freq %d\n",
832 dac_freq);
833 return;
834 }
835
836 venc_div = vclk_freq / venc_freq;
837
838 if (venc_div == 0) {
839 printf("Fatal Error, invalid HDMI venc freq %d\n",
840 venc_freq);
841 return;
842 }
843
844 switch (vclk_freq) {
845 case 54000:
846 if (hdmi_use_enci)
847 freq = MESON_VCLK_HDMI_ENCI_54000;
848 else
849 freq = MESON_VCLK_HDMI_DDR_54000;
850 break;
851 case 74250:
852 freq = MESON_VCLK_HDMI_74250;
853 break;
854 case 148500:
855 if (dac_freq != 148500)
856 freq = MESON_VCLK_HDMI_DDR_148500;
857 else
858 freq = MESON_VCLK_HDMI_148500;
859 break;
860 case 297000:
861 freq = MESON_VCLK_HDMI_297000;
862 break;
863 case 594000:
864 freq = MESON_VCLK_HDMI_594000;
865 break;
866 default:
867 printf("Fatal Error, invalid HDMI vclk freq %d\n",
868 vclk_freq);
869 return;
870 }
871
872 meson_vclk_set(priv, params[freq].pll_base_freq,
873 params[freq].pll_od1, params[freq].pll_od2,
874 params[freq].pll_od3, params[freq].vid_pll_div,
875 params[freq].vclk_div, hdmi_tx_div, venc_div,
876 hdmi_use_enci);
877}
878
879void meson_vpu_setup_vclk(struct udevice *dev,
880 const struct display_timing *mode, bool is_cvbs)
881{
882 struct meson_vpu_priv *priv = dev_get_priv(dev);
883 unsigned int vclk_freq;
884
885 if (is_cvbs)
886 return meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
887 0, 0, 0, false);
888
889 vclk_freq = mode->pixelclock.typ / 1000;
890
891 return meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT,
892 vclk_freq, vclk_freq, vclk_freq, false);
893}