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