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