blob: 58b4af5fbb6d16280b74bd11723b3e5a6bd52d05 [file] [log] [blame]
Thomas Gleixner1ccea772019-05-19 15:51:43 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Neil Armstrongbbbe7752016-11-10 15:29:37 +01002/*
3 * Copyright (C) 2016 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
Neil Armstrongbbbe7752016-11-10 15:29:37 +01006 */
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <drm/drmP.h>
11#include "meson_drv.h"
12#include "meson_vclk.h"
13
Neil Armstrong2021d5b2017-04-04 14:15:29 +020014/**
15 * DOC: Video Clocks
16 *
Neil Armstrongbbbe7752016-11-10 15:29:37 +010017 * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL.
18 * We handle the following encodings :
Neil Armstrong2021d5b2017-04-04 14:15:29 +020019 *
Neil Armstrongbbbe7752016-11-10 15:29:37 +010020 * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks
Neil Armstrongbbbe7752016-11-10 15:29:37 +010021 * - HDMI Pixel Clocks generation
Neil Armstrong2021d5b2017-04-04 14:15:29 +020022 *
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020023 * What is missing :
Neil Armstrong2021d5b2017-04-04 14:15:29 +020024 *
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020025 * - Genenate Pixel clocks for 2K/4K 10bit formats
26 *
27 * Clock generator scheme :
Neil Armstrong2021d5b2017-04-04 14:15:29 +020028 *
29 * .. code::
30 *
31 * __________ _________ _____
32 * | | | | | |--ENCI
33 * | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL
34 * |__________| |_________| \ | MUX |--ENCP
35 * --VCLK2-| |--VDAC
36 * |_____|--HDMI-TX
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020037 *
38 * Final clocks can take input for either VCLK or VCLK2, but
39 * VCLK is the preferred path for HDMI clocking and VCLK2 is the
40 * preferred path for CVBS VDAC clocking.
41 *
42 * VCLK and VCLK2 have fixed divided clocks paths for /1, /2, /4, /6 or /12.
43 *
44 * The PLL_DIV can achieve an additional fractional dividing like
45 * 1.5, 3.5, 3.75... to generate special 2K and 4K 10bit clocks.
Neil Armstrongbbbe7752016-11-10 15:29:37 +010046 */
47
48/* HHI Registers */
49#define HHI_VID_PLL_CLK_DIV 0x1a0 /* 0x68 offset in data sheet */
50#define VID_PLL_EN BIT(19)
51#define VID_PLL_BYPASS BIT(18)
52#define VID_PLL_PRESET BIT(15)
53#define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */
54#define VCLK2_DIV_MASK 0xff
55#define VCLK2_DIV_EN BIT(16)
56#define VCLK2_DIV_RESET BIT(17)
57#define CTS_VDAC_SEL_MASK (0xf << 28)
58#define CTS_VDAC_SEL_SHIFT 28
59#define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */
60#define VCLK2_EN BIT(19)
61#define VCLK2_SEL_MASK (0x7 << 16)
62#define VCLK2_SEL_SHIFT 16
63#define VCLK2_SOFT_RESET BIT(15)
64#define VCLK2_DIV1_EN BIT(0)
65#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020066#define VCLK_DIV_MASK 0xff
67#define VCLK_DIV_EN BIT(16)
68#define VCLK_DIV_RESET BIT(17)
69#define CTS_ENCP_SEL_MASK (0xf << 24)
70#define CTS_ENCP_SEL_SHIFT 24
Neil Armstrongbbbe7752016-11-10 15:29:37 +010071#define CTS_ENCI_SEL_MASK (0xf << 28)
72#define CTS_ENCI_SEL_SHIFT 28
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020073#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */
74#define VCLK_EN BIT(19)
75#define VCLK_SEL_MASK (0x7 << 16)
76#define VCLK_SEL_SHIFT 16
77#define VCLK_SOFT_RESET BIT(15)
78#define VCLK_DIV1_EN BIT(0)
79#define VCLK_DIV2_EN BIT(1)
80#define VCLK_DIV4_EN BIT(2)
81#define VCLK_DIV6_EN BIT(3)
82#define VCLK_DIV12_EN BIT(4)
Neil Armstrongbbbe7752016-11-10 15:29:37 +010083#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */
84#define CTS_ENCI_EN BIT(0)
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020085#define CTS_ENCP_EN BIT(2)
Neil Armstrongbbbe7752016-11-10 15:29:37 +010086#define CTS_VDAC_EN BIT(4)
Neil Armstrong2f4c95d2017-04-04 14:15:25 +020087#define HDMI_TX_PIXEL_EN BIT(5)
88#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */
89#define HDMI_TX_PIXEL_SEL_MASK (0xf << 16)
90#define HDMI_TX_PIXEL_SEL_SHIFT 16
91#define CTS_HDMI_SYS_SEL_MASK (0x7 << 9)
92#define CTS_HDMI_SYS_DIV_MASK (0x7f)
93#define CTS_HDMI_SYS_EN BIT(8)
Neil Armstrongbbbe7752016-11-10 15:29:37 +010094
95#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
96#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
97
98#define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
99#define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */
100#define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */
101#define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */
102#define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */
103#define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */
Neil Armstrong202b9802019-03-25 15:18:22 +0100104#define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100105
106#define HDMI_PLL_RESET BIT(28)
Neil Armstrong202b9802019-03-25 15:18:22 +0100107#define HDMI_PLL_RESET_G12A BIT(29)
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100108#define HDMI_PLL_LOCK BIT(31)
Neil Armstrong202b9802019-03-25 15:18:22 +0100109#define HDMI_PLL_LOCK_G12A (3 << 30)
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100110
Neil Armstrongff217bc2018-11-06 11:54:35 +0100111#define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001)
112
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200113/* VID PLL Dividers */
114enum {
115 VID_PLL_DIV_1 = 0,
116 VID_PLL_DIV_2,
117 VID_PLL_DIV_2p5,
118 VID_PLL_DIV_3,
119 VID_PLL_DIV_3p5,
120 VID_PLL_DIV_3p75,
121 VID_PLL_DIV_4,
122 VID_PLL_DIV_5,
123 VID_PLL_DIV_6,
124 VID_PLL_DIV_6p25,
125 VID_PLL_DIV_7,
126 VID_PLL_DIV_7p5,
127 VID_PLL_DIV_12,
128 VID_PLL_DIV_14,
129 VID_PLL_DIV_15,
130};
131
132void meson_vid_pll_set(struct meson_drm *priv, unsigned int div)
133{
134 unsigned int shift_val = 0;
135 unsigned int shift_sel = 0;
136
137 /* Disable vid_pll output clock */
138 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
139 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
140
141 switch (div) {
142 case VID_PLL_DIV_2:
143 shift_val = 0x0aaa;
144 shift_sel = 0;
145 break;
146 case VID_PLL_DIV_2p5:
147 shift_val = 0x5294;
148 shift_sel = 2;
149 break;
150 case VID_PLL_DIV_3:
151 shift_val = 0x0db6;
152 shift_sel = 0;
153 break;
154 case VID_PLL_DIV_3p5:
155 shift_val = 0x36cc;
156 shift_sel = 1;
157 break;
158 case VID_PLL_DIV_3p75:
159 shift_val = 0x6666;
160 shift_sel = 2;
161 break;
162 case VID_PLL_DIV_4:
163 shift_val = 0x0ccc;
164 shift_sel = 0;
165 break;
166 case VID_PLL_DIV_5:
167 shift_val = 0x739c;
168 shift_sel = 2;
169 break;
170 case VID_PLL_DIV_6:
171 shift_val = 0x0e38;
172 shift_sel = 0;
173 break;
174 case VID_PLL_DIV_6p25:
175 shift_val = 0x0000;
176 shift_sel = 3;
177 break;
178 case VID_PLL_DIV_7:
179 shift_val = 0x3c78;
180 shift_sel = 1;
181 break;
182 case VID_PLL_DIV_7p5:
183 shift_val = 0x78f0;
184 shift_sel = 2;
185 break;
186 case VID_PLL_DIV_12:
187 shift_val = 0x0fc0;
188 shift_sel = 0;
189 break;
190 case VID_PLL_DIV_14:
191 shift_val = 0x3f80;
192 shift_sel = 1;
193 break;
194 case VID_PLL_DIV_15:
195 shift_val = 0x7f80;
196 shift_sel = 2;
197 break;
198 }
199
200 if (div == VID_PLL_DIV_1)
201 /* Enable vid_pll bypass to HDMI pll */
202 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
203 VID_PLL_BYPASS, VID_PLL_BYPASS);
204 else {
205 /* Disable Bypass */
206 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
207 VID_PLL_BYPASS, 0);
208 /* Clear sel */
209 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
210 3 << 16, 0);
211 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
212 VID_PLL_PRESET, 0);
213 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
214 0x7fff, 0);
215
216 /* Setup sel and val */
217 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
218 3 << 16, shift_sel << 16);
219 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
220 VID_PLL_PRESET, VID_PLL_PRESET);
221 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
222 0x7fff, shift_val);
223
224 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
225 VID_PLL_PRESET, 0);
226 }
227
228 /* Enable the vid_pll output clock */
229 regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
230 VID_PLL_EN, VID_PLL_EN);
231}
232
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100233/*
234 * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC
235 *
236 * TOFIX: Refactor into table to also handle HDMI frequency and paths
237 */
238static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
239{
240 unsigned int val;
241
242 /* Setup PLL to output 1.485GHz */
243 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
244 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
245 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00404e00);
246 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
247 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
248 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
249 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
250 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d);
Neil Armstrong202b9802019-03-25 15:18:22 +0100251
252 /* Poll for lock bit */
253 regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
254 (val & HDMI_PLL_LOCK), 10, 0);
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100255 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
256 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
257 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
258 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
259 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0xa6212844);
260 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c4d000c);
261 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
262 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
263
264 /* Reset PLL */
265 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
266 HDMI_PLL_RESET, HDMI_PLL_RESET);
267 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
268 HDMI_PLL_RESET, 0);
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100269
Neil Armstrong202b9802019-03-25 15:18:22 +0100270 /* Poll for lock bit */
271 regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
272 (val & HDMI_PLL_LOCK), 10, 0);
273 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
274 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7);
275 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000);
276 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
277 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x6a28dc00);
278 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290);
279 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000);
280 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x56540000);
281 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3a0504f7);
282 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7);
283
284 /* Poll for lock bit */
285 regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
286 ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A),
287 10, 0);
288 }
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100289
290 /* Disable VCLK2 */
291 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
292
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200293 /* Setup vid_pll to /1 */
294 meson_vid_pll_set(priv, VID_PLL_DIV_1);
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100295
296 /* Setup the VCLK2 divider value to achieve 27MHz */
297 regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
298 VCLK2_DIV_MASK, (55 - 1));
299
300 /* select vid_pll for vclk2 */
Neil Armstrong202b9802019-03-25 15:18:22 +0100301 if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
302 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
303 VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT));
304 else
305 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
306 VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
307
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100308 /* enable vclk2 gate */
309 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
310
311 /* select vclk_div1 for enci */
312 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
313 CTS_ENCI_SEL_MASK, (8 << CTS_ENCI_SEL_SHIFT));
314 /* select vclk_div1 for vdac */
315 regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
316 CTS_VDAC_SEL_MASK, (8 << CTS_VDAC_SEL_SHIFT));
317
318 /* release vclk2_div_reset and enable vclk2_div */
319 regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
320 VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN);
321
322 /* enable vclk2_div1 gate */
323 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
324 VCLK2_DIV1_EN, VCLK2_DIV1_EN);
325
326 /* reset vclk2 */
327 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
328 VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
329 regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
330 VCLK2_SOFT_RESET, 0);
331
332 /* enable enci_clk */
333 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
334 CTS_ENCI_EN, CTS_ENCI_EN);
335 /* enable vdac_clk */
336 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
337 CTS_VDAC_EN, CTS_VDAC_EN);
338}
339
Neil Armstrong3273fc62018-07-16 09:40:14 +0200340enum {
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200341/* PLL O1 O2 O3 VP DV EN TX */
342/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
Neil Armstrongff217bc2018-11-06 11:54:35 +0100343 MESON_VCLK_HDMI_ENCI_54000 = 0,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200344/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200345 MESON_VCLK_HDMI_DDR_54000,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200346/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200347 MESON_VCLK_HDMI_DDR_148500,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200348/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200349 MESON_VCLK_HDMI_74250,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200350/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200351 MESON_VCLK_HDMI_148500,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200352/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200353 MESON_VCLK_HDMI_297000,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200354/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200355 MESON_VCLK_HDMI_594000
356};
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200357
358struct meson_vclk_params {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100359 unsigned int pixel_freq;
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200360 unsigned int pll_base_freq;
361 unsigned int pll_od1;
362 unsigned int pll_od2;
363 unsigned int pll_od3;
364 unsigned int vid_pll_div;
365 unsigned int vclk_div;
366} params[] = {
367 [MESON_VCLK_HDMI_ENCI_54000] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100368 .pixel_freq = 54000,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200369 .pll_base_freq = 4320000,
370 .pll_od1 = 4,
371 .pll_od2 = 4,
372 .pll_od3 = 1,
373 .vid_pll_div = VID_PLL_DIV_5,
374 .vclk_div = 1,
375 },
376 [MESON_VCLK_HDMI_DDR_54000] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100377 .pixel_freq = 54000,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200378 .pll_base_freq = 4320000,
379 .pll_od1 = 4,
380 .pll_od2 = 4,
381 .pll_od3 = 1,
382 .vid_pll_div = VID_PLL_DIV_5,
383 .vclk_div = 1,
384 },
385 [MESON_VCLK_HDMI_DDR_148500] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100386 .pixel_freq = 148500,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200387 .pll_base_freq = 2970000,
388 .pll_od1 = 4,
389 .pll_od2 = 1,
390 .pll_od3 = 1,
391 .vid_pll_div = VID_PLL_DIV_5,
392 .vclk_div = 1,
393 },
394 [MESON_VCLK_HDMI_74250] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100395 .pixel_freq = 74250,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200396 .pll_base_freq = 2970000,
397 .pll_od1 = 2,
398 .pll_od2 = 2,
399 .pll_od3 = 2,
400 .vid_pll_div = VID_PLL_DIV_5,
401 .vclk_div = 1,
402 },
403 [MESON_VCLK_HDMI_148500] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100404 .pixel_freq = 148500,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200405 .pll_base_freq = 2970000,
406 .pll_od1 = 1,
407 .pll_od2 = 2,
408 .pll_od3 = 2,
409 .vid_pll_div = VID_PLL_DIV_5,
410 .vclk_div = 1,
411 },
412 [MESON_VCLK_HDMI_297000] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100413 .pixel_freq = 297000,
Neil Armstrong61af6e22019-03-25 15:18:14 +0100414 .pll_base_freq = 5940000,
415 .pll_od1 = 2,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200416 .pll_od2 = 1,
417 .pll_od3 = 1,
418 .vid_pll_div = VID_PLL_DIV_5,
419 .vclk_div = 2,
420 },
421 [MESON_VCLK_HDMI_594000] = {
Neil Armstrongff217bc2018-11-06 11:54:35 +0100422 .pixel_freq = 594000,
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200423 .pll_base_freq = 5940000,
424 .pll_od1 = 1,
425 .pll_od2 = 1,
426 .pll_od3 = 2,
427 .vid_pll_div = VID_PLL_DIV_5,
428 .vclk_div = 1,
429 },
Neil Armstrongff217bc2018-11-06 11:54:35 +0100430 { /* sentinel */ },
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200431};
432
433static inline unsigned int pll_od_to_reg(unsigned int od)
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100434{
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200435 switch (od) {
436 case 1:
437 return 0;
438 case 2:
439 return 1;
440 case 4:
441 return 2;
442 case 8:
443 return 3;
444 }
445
446 /* Invalid */
447 return 0;
Neil Armstrongbbbe7752016-11-10 15:29:37 +0100448}
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200449
Neil Armstrong3273fc62018-07-16 09:40:14 +0200450void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
451 unsigned int frac, unsigned int od1,
452 unsigned int od2, unsigned int od3)
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200453{
454 unsigned int val;
455
456 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
Neil Armstrong3273fc62018-07-16 09:40:14 +0200457 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
458 if (frac)
459 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
460 0x00004000 | frac);
461 else
462 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
463 0x00000000);
464 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
465 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
466 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
467 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200468
Neil Armstrong3273fc62018-07-16 09:40:14 +0200469 /* Enable and unreset */
470 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
471 0x7 << 28, 0x4 << 28);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200472
Neil Armstrong3273fc62018-07-16 09:40:14 +0200473 /* Poll for lock bit */
474 regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
475 val, (val & HDMI_PLL_LOCK), 10, 0);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200476 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
477 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
Neil Armstrong3273fc62018-07-16 09:40:14 +0200478 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
479 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
480 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
481 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
482 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
483 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200484
485 /* Reset PLL */
486 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200487 HDMI_PLL_RESET, HDMI_PLL_RESET);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200488 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200489 HDMI_PLL_RESET, 0);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200490
491 /* Poll for lock bit */
492 regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
493 (val & HDMI_PLL_LOCK), 10, 0);
Neil Armstrong202b9802019-03-25 15:18:22 +0100494 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
495 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m);
496
497 /* Enable and reset */
498 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
499 0x3 << 28, 0x3 << 28);
500
501 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac);
502 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
503
504 /* G12A HDMI PLL Needs specific parameters for 5.4GHz */
505 if (m >= 0xf7) {
506 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0xea68dc00);
507 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290);
508 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000);
509 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000);
510 } else {
511 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00);
512 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290);
513 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000);
514 regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000);
515 }
516
517 do {
518 /* Reset PLL */
519 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
520 HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A);
521
522 /* UN-Reset PLL */
523 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
524 HDMI_PLL_RESET_G12A, 0);
525
526 /* Poll for lock bits */
527 if (!regmap_read_poll_timeout(priv->hhi,
528 HHI_HDMI_PLL_CNTL, val,
529 ((val & HDMI_PLL_LOCK_G12A)
530 == HDMI_PLL_LOCK_G12A),
531 10, 100))
532 break;
533 } while(1);
Neil Armstrong3273fc62018-07-16 09:40:14 +0200534 }
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200535
536 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
537 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200538 3 << 16, pll_od_to_reg(od1) << 16);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200539 else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
Neil Armstrong202b9802019-03-25 15:18:22 +0100540 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200541 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200542 3 << 21, pll_od_to_reg(od1) << 21);
Neil Armstrong202b9802019-03-25 15:18:22 +0100543 else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
544 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
545 3 << 16, pll_od_to_reg(od1) << 16);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200546
547 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
548 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200549 3 << 22, pll_od_to_reg(od2) << 22);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200550 else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
Neil Armstrong202b9802019-03-25 15:18:22 +0100551 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200552 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200553 3 << 23, pll_od_to_reg(od2) << 23);
Neil Armstrong202b9802019-03-25 15:18:22 +0100554 else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
555 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
556 3 << 18, pll_od_to_reg(od2) << 18);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200557
558 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
559 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200560 3 << 18, pll_od_to_reg(od3) << 18);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200561 else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
Neil Armstrong202b9802019-03-25 15:18:22 +0100562 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200563 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200564 3 << 19, pll_od_to_reg(od3) << 19);
Neil Armstrong202b9802019-03-25 15:18:22 +0100565 else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
566 regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
567 3 << 20, pll_od_to_reg(od3) << 20);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200568}
569
Neil Armstrong3273fc62018-07-16 09:40:14 +0200570#define XTAL_FREQ 24000
571
572static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv,
573 unsigned int pll_freq)
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200574{
Neil Armstrong3273fc62018-07-16 09:40:14 +0200575 /* The GXBB PLL has a /2 pre-multiplier */
576 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
577 pll_freq /= 2;
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200578
Neil Armstrong3273fc62018-07-16 09:40:14 +0200579 return pll_freq / XTAL_FREQ;
580}
581
582#define HDMI_FRAC_MAX_GXBB 4096
583#define HDMI_FRAC_MAX_GXL 1024
Neil Armstrong202b9802019-03-25 15:18:22 +0100584#define HDMI_FRAC_MAX_G12A 131072
Neil Armstrong3273fc62018-07-16 09:40:14 +0200585
586static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv,
587 unsigned int m,
588 unsigned int pll_freq)
589{
590 unsigned int parent_freq = XTAL_FREQ;
591 unsigned int frac_max = HDMI_FRAC_MAX_GXL;
592 unsigned int frac_m;
593 unsigned int frac;
594
595 /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */
596 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
597 frac_max = HDMI_FRAC_MAX_GXBB;
598 parent_freq *= 2;
599 }
600
Neil Armstrong202b9802019-03-25 15:18:22 +0100601 if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
602 frac_max = HDMI_FRAC_MAX_G12A;
603
Neil Armstrong3273fc62018-07-16 09:40:14 +0200604 /* We can have a perfect match !*/
605 if (pll_freq / m == parent_freq &&
606 pll_freq % m == 0)
607 return 0;
608
609 frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq);
610 frac_m = m * frac_max;
611 if (frac_m > frac)
612 return frac_max;
613 frac -= frac_m;
614
615 return min((u16)frac, (u16)(frac_max - 1));
616}
617
618static bool meson_hdmi_pll_validate_params(struct meson_drm *priv,
619 unsigned int m,
620 unsigned int frac)
621{
622 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
623 /* Empiric supported min/max dividers */
624 if (m < 53 || m > 123)
625 return false;
626 if (frac >= HDMI_FRAC_MAX_GXBB)
627 return false;
628 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
Neil Armstrong202b9802019-03-25 15:18:22 +0100629 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") ||
630 meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
Neil Armstrong3273fc62018-07-16 09:40:14 +0200631 /* Empiric supported min/max dividers */
632 if (m < 106 || m > 247)
633 return false;
634 if (frac >= HDMI_FRAC_MAX_GXL)
635 return false;
636 }
637
638 return true;
639}
640
641static bool meson_hdmi_pll_find_params(struct meson_drm *priv,
642 unsigned int freq,
643 unsigned int *m,
644 unsigned int *frac,
645 unsigned int *od)
646{
647 /* Cycle from /16 to /2 */
648 for (*od = 16 ; *od > 1 ; *od >>= 1) {
649 *m = meson_hdmi_pll_get_m(priv, freq * *od);
650 if (!*m)
651 continue;
652 *frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od);
653
654 DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d\n",
655 freq, *m, *frac, *od);
656
657 if (meson_hdmi_pll_validate_params(priv, *m, *frac))
658 return true;
659 }
660
661 return false;
662}
663
664/* pll_freq is the frequency after the OD dividers */
665enum drm_mode_status
666meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq)
667{
668 unsigned int od, m, frac;
669
670 /* In DMT mode, path after PLL is always /10 */
671 freq *= 10;
672
673 if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
674 return MODE_OK;
675
676 return MODE_CLOCK_RANGE;
677}
678EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq);
679
680/* pll_freq is the frequency after the OD dividers */
681static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
682 unsigned int pll_freq)
683{
684 unsigned int od, m, frac, od1, od2, od3;
685
686 if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
687 od3 = 1;
688 if (od < 4) {
689 od1 = 2;
690 od2 = 1;
691 } else {
692 od2 = od / 4;
693 od1 = od / od2;
694 }
695
696 DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n",
697 pll_freq, m, frac, od1, od2, od3);
698
699 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
700
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200701 return;
702 }
703
Neil Armstrong3273fc62018-07-16 09:40:14 +0200704 DRM_ERROR("Fatal, unable to find parameters for PLL freq %d\n",
705 pll_freq);
706}
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200707
Neil Armstrongff217bc2018-11-06 11:54:35 +0100708enum drm_mode_status
709meson_vclk_vic_supported_freq(unsigned int freq)
710{
711 int i;
712
713 DRM_DEBUG_DRIVER("freq = %d\n", freq);
714
715 for (i = 0 ; params[i].pixel_freq ; ++i) {
716 DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
717 i, params[i].pixel_freq,
718 FREQ_1000_1001(params[i].pixel_freq));
719 /* Match strict frequency */
720 if (freq == params[i].pixel_freq)
721 return MODE_OK;
722 /* Match 1000/1001 variant */
723 if (freq == FREQ_1000_1001(params[i].pixel_freq))
724 return MODE_OK;
725 }
726
727 return MODE_CLOCK_RANGE;
728}
729EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq);
730
Neil Armstrong3273fc62018-07-16 09:40:14 +0200731static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
732 unsigned int od1, unsigned int od2, unsigned int od3,
733 unsigned int vid_pll_div, unsigned int vclk_div,
734 unsigned int hdmi_tx_div, unsigned int venc_div,
Neil Armstrongff217bc2018-11-06 11:54:35 +0100735 bool hdmi_use_enci, bool vic_alternate_clock)
Neil Armstrong3273fc62018-07-16 09:40:14 +0200736{
Neil Armstrongff217bc2018-11-06 11:54:35 +0100737 unsigned int m = 0, frac = 0;
738
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200739 /* Set HDMI-TX sys clock */
740 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
741 CTS_HDMI_SYS_SEL_MASK, 0);
742 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
743 CTS_HDMI_SYS_DIV_MASK, 0);
744 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
745 CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
746
747 /* Set HDMI PLL rate */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200748 if (!od1 && !od2 && !od3) {
749 meson_hdmi_pll_generic_set(priv, pll_base_freq);
750 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
751 switch (pll_base_freq) {
752 case 2970000:
Neil Armstrongff217bc2018-11-06 11:54:35 +0100753 m = 0x3d;
754 frac = vic_alternate_clock ? 0xd02 : 0xe00;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200755 break;
756 case 4320000:
Neil Armstrongff217bc2018-11-06 11:54:35 +0100757 m = vic_alternate_clock ? 0x59 : 0x5a;
758 frac = vic_alternate_clock ? 0xe8f : 0;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200759 break;
760 case 5940000:
Neil Armstrongff217bc2018-11-06 11:54:35 +0100761 m = 0x7b;
762 frac = vic_alternate_clock ? 0xa05 : 0xc00;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200763 break;
764 }
Neil Armstrongff217bc2018-11-06 11:54:35 +0100765
766 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
Neil Armstrong3273fc62018-07-16 09:40:14 +0200767 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
768 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
769 switch (pll_base_freq) {
770 case 2970000:
Neil Armstrongff217bc2018-11-06 11:54:35 +0100771 m = 0x7b;
772 frac = vic_alternate_clock ? 0x281 : 0x300;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200773 break;
774 case 4320000:
Neil Armstrongff217bc2018-11-06 11:54:35 +0100775 m = vic_alternate_clock ? 0xb3 : 0xb4;
776 frac = vic_alternate_clock ? 0x347 : 0;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200777 break;
778 case 5940000:
Neil Armstrongff217bc2018-11-06 11:54:35 +0100779 m = 0xf7;
780 frac = vic_alternate_clock ? 0x102 : 0x200;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200781 break;
782 }
Neil Armstrongff217bc2018-11-06 11:54:35 +0100783
784 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
Neil Armstrong202b9802019-03-25 15:18:22 +0100785 } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
786 switch (pll_base_freq) {
787 case 2970000:
788 m = 0x7b;
789 frac = vic_alternate_clock ? 0x140b4 : 0x18000;
790 break;
791 case 4320000:
792 m = vic_alternate_clock ? 0xb3 : 0xb4;
793 frac = vic_alternate_clock ? 0x1a3ee : 0;
794 break;
795 case 5940000:
796 m = 0xf7;
797 frac = vic_alternate_clock ? 0x8148 : 0x10000;
798 break;
799 }
800
801 meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
Neil Armstrong3273fc62018-07-16 09:40:14 +0200802 }
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200803
804 /* Setup vid_pll divider */
Neil Armstrong3273fc62018-07-16 09:40:14 +0200805 meson_vid_pll_set(priv, vid_pll_div);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200806
807 /* Set VCLK div */
808 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
809 VCLK_SEL_MASK, 0);
810 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
Neil Armstrong3273fc62018-07-16 09:40:14 +0200811 VCLK_DIV_MASK, vclk_div - 1);
Neil Armstrong2f4c95d2017-04-04 14:15:25 +0200812
813 /* Set HDMI-TX source */
814 switch (hdmi_tx_div) {
815 case 1:
816 /* enable vclk_div1 gate */
817 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
818 VCLK_DIV1_EN, VCLK_DIV1_EN);
819
820 /* select vclk_div1 for HDMI-TX */
821 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
822 HDMI_TX_PIXEL_SEL_MASK, 0);
823 break;
824 case 2:
825 /* enable vclk_div2 gate */
826 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
827 VCLK_DIV2_EN, VCLK_DIV2_EN);
828
829 /* select vclk_div2 for HDMI-TX */
830 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
831 HDMI_TX_PIXEL_SEL_MASK, 1 << HDMI_TX_PIXEL_SEL_SHIFT);
832 break;
833 case 4:
834 /* enable vclk_div4 gate */
835 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
836 VCLK_DIV4_EN, VCLK_DIV4_EN);
837
838 /* select vclk_div4 for HDMI-TX */
839 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
840 HDMI_TX_PIXEL_SEL_MASK, 2 << HDMI_TX_PIXEL_SEL_SHIFT);
841 break;
842 case 6:
843 /* enable vclk_div6 gate */
844 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
845 VCLK_DIV6_EN, VCLK_DIV6_EN);
846
847 /* select vclk_div6 for HDMI-TX */
848 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
849 HDMI_TX_PIXEL_SEL_MASK, 3 << HDMI_TX_PIXEL_SEL_SHIFT);
850 break;
851 case 12:
852 /* enable vclk_div12 gate */
853 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
854 VCLK_DIV12_EN, VCLK_DIV12_EN);
855
856 /* select vclk_div12 for HDMI-TX */
857 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
858 HDMI_TX_PIXEL_SEL_MASK, 4 << HDMI_TX_PIXEL_SEL_SHIFT);
859 break;
860 }
861 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
862 HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
863
864 /* Set ENCI/ENCP Source */
865 switch (venc_div) {
866 case 1:
867 /* enable vclk_div1 gate */
868 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
869 VCLK_DIV1_EN, VCLK_DIV1_EN);
870
871 if (hdmi_use_enci)
872 /* select vclk_div1 for enci */
873 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
874 CTS_ENCI_SEL_MASK, 0);
875 else
876 /* select vclk_div1 for encp */
877 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
878 CTS_ENCP_SEL_MASK, 0);
879 break;
880 case 2:
881 /* enable vclk_div2 gate */
882 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
883 VCLK_DIV2_EN, VCLK_DIV2_EN);
884
885 if (hdmi_use_enci)
886 /* select vclk_div2 for enci */
887 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
888 CTS_ENCI_SEL_MASK, 1 << CTS_ENCI_SEL_SHIFT);
889 else
890 /* select vclk_div2 for encp */
891 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
892 CTS_ENCP_SEL_MASK, 1 << CTS_ENCP_SEL_SHIFT);
893 break;
894 case 4:
895 /* enable vclk_div4 gate */
896 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
897 VCLK_DIV4_EN, VCLK_DIV4_EN);
898
899 if (hdmi_use_enci)
900 /* select vclk_div4 for enci */
901 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
902 CTS_ENCI_SEL_MASK, 2 << CTS_ENCI_SEL_SHIFT);
903 else
904 /* select vclk_div4 for encp */
905 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
906 CTS_ENCP_SEL_MASK, 2 << CTS_ENCP_SEL_SHIFT);
907 break;
908 case 6:
909 /* enable vclk_div6 gate */
910 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
911 VCLK_DIV6_EN, VCLK_DIV6_EN);
912
913 if (hdmi_use_enci)
914 /* select vclk_div6 for enci */
915 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
916 CTS_ENCI_SEL_MASK, 3 << CTS_ENCI_SEL_SHIFT);
917 else
918 /* select vclk_div6 for encp */
919 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
920 CTS_ENCP_SEL_MASK, 3 << CTS_ENCP_SEL_SHIFT);
921 break;
922 case 12:
923 /* enable vclk_div12 gate */
924 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
925 VCLK_DIV12_EN, VCLK_DIV12_EN);
926
927 if (hdmi_use_enci)
928 /* select vclk_div12 for enci */
929 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
930 CTS_ENCI_SEL_MASK, 4 << CTS_ENCI_SEL_SHIFT);
931 else
932 /* select vclk_div12 for encp */
933 regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
934 CTS_ENCP_SEL_MASK, 4 << CTS_ENCP_SEL_SHIFT);
935 break;
936 }
937
938 if (hdmi_use_enci)
939 /* Enable ENCI clock gate */
940 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
941 CTS_ENCI_EN, CTS_ENCI_EN);
942 else
943 /* Enable ENCP clock gate */
944 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
945 CTS_ENCP_EN, CTS_ENCP_EN);
946
947 regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
948}
Neil Armstrong3273fc62018-07-16 09:40:14 +0200949
950void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
951 unsigned int vclk_freq, unsigned int venc_freq,
952 unsigned int dac_freq, bool hdmi_use_enci)
953{
Neil Armstrongff217bc2018-11-06 11:54:35 +0100954 bool vic_alternate_clock = false;
Neil Armstrong3273fc62018-07-16 09:40:14 +0200955 unsigned int freq;
956 unsigned int hdmi_tx_div;
957 unsigned int venc_div;
958
959 if (target == MESON_VCLK_TARGET_CVBS) {
960 meson_venci_cvbs_clock_config(priv);
961 return;
962 } else if (target == MESON_VCLK_TARGET_DMT) {
963 /* The DMT clock path is fixed after the PLL:
964 * - automatic PLL freq + OD management
965 * - vid_pll_div = VID_PLL_DIV_5
966 * - vclk_div = 2
967 * - hdmi_tx_div = 1
968 * - venc_div = 1
969 * - encp encoder
970 */
971 meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
Neil Armstrongff217bc2018-11-06 11:54:35 +0100972 VID_PLL_DIV_5, 2, 1, 1, false, false);
Neil Armstrong3273fc62018-07-16 09:40:14 +0200973 return;
974 }
975
976 hdmi_tx_div = vclk_freq / dac_freq;
977
978 if (hdmi_tx_div == 0) {
979 pr_err("Fatal Error, invalid HDMI-TX freq %d\n",
980 dac_freq);
981 return;
982 }
983
984 venc_div = vclk_freq / venc_freq;
985
986 if (venc_div == 0) {
987 pr_err("Fatal Error, invalid HDMI venc freq %d\n",
988 venc_freq);
989 return;
990 }
991
Neil Armstrongff217bc2018-11-06 11:54:35 +0100992 for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
993 if (vclk_freq == params[freq].pixel_freq ||
994 vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
995 if (vclk_freq != params[freq].pixel_freq)
996 vic_alternate_clock = true;
997 else
998 vic_alternate_clock = false;
999
1000 if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
1001 !hdmi_use_enci)
1002 continue;
1003
1004 if (freq == MESON_VCLK_HDMI_DDR_54000 &&
1005 hdmi_use_enci)
1006 continue;
1007
1008 if (freq == MESON_VCLK_HDMI_DDR_148500 &&
1009 dac_freq == vclk_freq)
1010 continue;
1011
1012 if (freq == MESON_VCLK_HDMI_148500 &&
1013 dac_freq != vclk_freq)
1014 continue;
1015 break;
1016 }
1017 }
1018
1019 if (!params[freq].pixel_freq) {
1020 pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
Neil Armstrong3273fc62018-07-16 09:40:14 +02001021 return;
1022 }
1023
1024 meson_vclk_set(priv, params[freq].pll_base_freq,
1025 params[freq].pll_od1, params[freq].pll_od2,
1026 params[freq].pll_od3, params[freq].vid_pll_div,
1027 params[freq].vclk_div, hdmi_tx_div, venc_div,
Neil Armstrongff217bc2018-11-06 11:54:35 +01001028 hdmi_use_enci, vic_alternate_clock);
Neil Armstrong3273fc62018-07-16 09:40:14 +02001029}
Neil Armstrong2f4c95d2017-04-04 14:15:25 +02001030EXPORT_SYMBOL_GPL(meson_vclk_setup);