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