diff options
author | Neil Armstrong <narmstrong@baylibre.com> | 2017-04-04 08:15:25 -0400 |
---|---|---|
committer | Neil Armstrong <narmstrong@baylibre.com> | 2017-04-04 11:49:31 -0400 |
commit | 2f4c95dc3d1d1518cb6a5e280050c48a79d3ee08 (patch) | |
tree | 7cb26b6c02db1737985130d3736b415ffe557647 | |
parent | cb110b665e77ebf99f8235f257b88eea007186d3 (diff) |
drm/meson: add support for HDMI clock support
This patchs adds support for the supported HDMI modes clocks frequencies.
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
-rw-r--r-- | drivers/gpu/drm/meson/meson_vclk.c | 624 | ||||
-rw-r--r-- | drivers/gpu/drm/meson/meson_vclk.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/meson/meson_venc_cvbs.c | 9 |
3 files changed, 623 insertions, 16 deletions
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 252cfd4b19b1..3731479746ca 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c | |||
@@ -27,9 +27,26 @@ | |||
27 | * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL. | 27 | * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL. |
28 | * We handle the following encodings : | 28 | * We handle the following encodings : |
29 | * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks | 29 | * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks |
30 | * | ||
31 | * What is missing : | ||
32 | * - HDMI Pixel Clocks generation | 30 | * - HDMI Pixel Clocks generation |
31 | * What is missing : | ||
32 | * - Genenate Pixel clocks for 2K/4K 10bit formats | ||
33 | * | ||
34 | * Clock generator scheme : | ||
35 | * __________ _________ _____ | ||
36 | * | | | | | |--ENCI | ||
37 | * | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL | ||
38 | * |__________| |_________| \ | MUX |--ENCP | ||
39 | * --VCLK2-| |--VDAC | ||
40 | * |_____|--HDMI-TX | ||
41 | * | ||
42 | * Final clocks can take input for either VCLK or VCLK2, but | ||
43 | * VCLK is the preferred path for HDMI clocking and VCLK2 is the | ||
44 | * preferred path for CVBS VDAC clocking. | ||
45 | * | ||
46 | * VCLK and VCLK2 have fixed divided clocks paths for /1, /2, /4, /6 or /12. | ||
47 | * | ||
48 | * The PLL_DIV can achieve an additional fractional dividing like | ||
49 | * 1.5, 3.5, 3.75... to generate special 2K and 4K 10bit clocks. | ||
33 | */ | 50 | */ |
34 | 51 | ||
35 | /* HHI Registers */ | 52 | /* HHI Registers */ |
@@ -50,11 +67,34 @@ | |||
50 | #define VCLK2_SOFT_RESET BIT(15) | 67 | #define VCLK2_SOFT_RESET BIT(15) |
51 | #define VCLK2_DIV1_EN BIT(0) | 68 | #define VCLK2_DIV1_EN BIT(0) |
52 | #define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ | 69 | #define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ |
70 | #define VCLK_DIV_MASK 0xff | ||
71 | #define VCLK_DIV_EN BIT(16) | ||
72 | #define VCLK_DIV_RESET BIT(17) | ||
73 | #define CTS_ENCP_SEL_MASK (0xf << 24) | ||
74 | #define CTS_ENCP_SEL_SHIFT 24 | ||
53 | #define CTS_ENCI_SEL_MASK (0xf << 28) | 75 | #define CTS_ENCI_SEL_MASK (0xf << 28) |
54 | #define CTS_ENCI_SEL_SHIFT 28 | 76 | #define CTS_ENCI_SEL_SHIFT 28 |
77 | #define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ | ||
78 | #define VCLK_EN BIT(19) | ||
79 | #define VCLK_SEL_MASK (0x7 << 16) | ||
80 | #define VCLK_SEL_SHIFT 16 | ||
81 | #define VCLK_SOFT_RESET BIT(15) | ||
82 | #define VCLK_DIV1_EN BIT(0) | ||
83 | #define VCLK_DIV2_EN BIT(1) | ||
84 | #define VCLK_DIV4_EN BIT(2) | ||
85 | #define VCLK_DIV6_EN BIT(3) | ||
86 | #define VCLK_DIV12_EN BIT(4) | ||
55 | #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ | 87 | #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ |
56 | #define CTS_ENCI_EN BIT(0) | 88 | #define CTS_ENCI_EN BIT(0) |
89 | #define CTS_ENCP_EN BIT(2) | ||
57 | #define CTS_VDAC_EN BIT(4) | 90 | #define CTS_VDAC_EN BIT(4) |
91 | #define HDMI_TX_PIXEL_EN BIT(5) | ||
92 | #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ | ||
93 | #define HDMI_TX_PIXEL_SEL_MASK (0xf << 16) | ||
94 | #define HDMI_TX_PIXEL_SEL_SHIFT 16 | ||
95 | #define CTS_HDMI_SYS_SEL_MASK (0x7 << 9) | ||
96 | #define CTS_HDMI_SYS_DIV_MASK (0x7f) | ||
97 | #define CTS_HDMI_SYS_EN BIT(8) | ||
58 | 98 | ||
59 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ | 99 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ |
60 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ | 100 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ |
@@ -69,6 +109,126 @@ | |||
69 | #define HDMI_PLL_RESET BIT(28) | 109 | #define HDMI_PLL_RESET BIT(28) |
70 | #define HDMI_PLL_LOCK BIT(31) | 110 | #define HDMI_PLL_LOCK BIT(31) |
71 | 111 | ||
112 | /* VID PLL Dividers */ | ||
113 | enum { | ||
114 | VID_PLL_DIV_1 = 0, | ||
115 | VID_PLL_DIV_2, | ||
116 | VID_PLL_DIV_2p5, | ||
117 | VID_PLL_DIV_3, | ||
118 | VID_PLL_DIV_3p5, | ||
119 | VID_PLL_DIV_3p75, | ||
120 | VID_PLL_DIV_4, | ||
121 | VID_PLL_DIV_5, | ||
122 | VID_PLL_DIV_6, | ||
123 | VID_PLL_DIV_6p25, | ||
124 | VID_PLL_DIV_7, | ||
125 | VID_PLL_DIV_7p5, | ||
126 | VID_PLL_DIV_12, | ||
127 | VID_PLL_DIV_14, | ||
128 | VID_PLL_DIV_15, | ||
129 | }; | ||
130 | |||
131 | void meson_vid_pll_set(struct meson_drm *priv, unsigned int div) | ||
132 | { | ||
133 | unsigned int shift_val = 0; | ||
134 | unsigned int shift_sel = 0; | ||
135 | |||
136 | /* Disable vid_pll output clock */ | ||
137 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0); | ||
138 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0); | ||
139 | |||
140 | switch (div) { | ||
141 | case VID_PLL_DIV_2: | ||
142 | shift_val = 0x0aaa; | ||
143 | shift_sel = 0; | ||
144 | break; | ||
145 | case VID_PLL_DIV_2p5: | ||
146 | shift_val = 0x5294; | ||
147 | shift_sel = 2; | ||
148 | break; | ||
149 | case VID_PLL_DIV_3: | ||
150 | shift_val = 0x0db6; | ||
151 | shift_sel = 0; | ||
152 | break; | ||
153 | case VID_PLL_DIV_3p5: | ||
154 | shift_val = 0x36cc; | ||
155 | shift_sel = 1; | ||
156 | break; | ||
157 | case VID_PLL_DIV_3p75: | ||
158 | shift_val = 0x6666; | ||
159 | shift_sel = 2; | ||
160 | break; | ||
161 | case VID_PLL_DIV_4: | ||
162 | shift_val = 0x0ccc; | ||
163 | shift_sel = 0; | ||
164 | break; | ||
165 | case VID_PLL_DIV_5: | ||
166 | shift_val = 0x739c; | ||
167 | shift_sel = 2; | ||
168 | break; | ||
169 | case VID_PLL_DIV_6: | ||
170 | shift_val = 0x0e38; | ||
171 | shift_sel = 0; | ||
172 | break; | ||
173 | case VID_PLL_DIV_6p25: | ||
174 | shift_val = 0x0000; | ||
175 | shift_sel = 3; | ||
176 | break; | ||
177 | case VID_PLL_DIV_7: | ||
178 | shift_val = 0x3c78; | ||
179 | shift_sel = 1; | ||
180 | break; | ||
181 | case VID_PLL_DIV_7p5: | ||
182 | shift_val = 0x78f0; | ||
183 | shift_sel = 2; | ||
184 | break; | ||
185 | case VID_PLL_DIV_12: | ||
186 | shift_val = 0x0fc0; | ||
187 | shift_sel = 0; | ||
188 | break; | ||
189 | case VID_PLL_DIV_14: | ||
190 | shift_val = 0x3f80; | ||
191 | shift_sel = 1; | ||
192 | break; | ||
193 | case VID_PLL_DIV_15: | ||
194 | shift_val = 0x7f80; | ||
195 | shift_sel = 2; | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | if (div == VID_PLL_DIV_1) | ||
200 | /* Enable vid_pll bypass to HDMI pll */ | ||
201 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
202 | VID_PLL_BYPASS, VID_PLL_BYPASS); | ||
203 | else { | ||
204 | /* Disable Bypass */ | ||
205 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
206 | VID_PLL_BYPASS, 0); | ||
207 | /* Clear sel */ | ||
208 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
209 | 3 << 16, 0); | ||
210 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
211 | VID_PLL_PRESET, 0); | ||
212 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
213 | 0x7fff, 0); | ||
214 | |||
215 | /* Setup sel and val */ | ||
216 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
217 | 3 << 16, shift_sel << 16); | ||
218 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
219 | VID_PLL_PRESET, VID_PLL_PRESET); | ||
220 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
221 | 0x7fff, shift_val); | ||
222 | |||
223 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
224 | VID_PLL_PRESET, 0); | ||
225 | } | ||
226 | |||
227 | /* Enable the vid_pll output clock */ | ||
228 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
229 | VID_PLL_EN, VID_PLL_EN); | ||
230 | } | ||
231 | |||
72 | /* | 232 | /* |
73 | * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC | 233 | * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC |
74 | * | 234 | * |
@@ -110,15 +270,8 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) | |||
110 | /* Disable VCLK2 */ | 270 | /* Disable VCLK2 */ |
111 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); | 271 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); |
112 | 272 | ||
113 | /* Disable vid_pll output clock */ | 273 | /* Setup vid_pll to /1 */ |
114 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0); | 274 | meson_vid_pll_set(priv, VID_PLL_DIV_1); |
115 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0); | ||
116 | /* Enable vid_pll bypass to HDMI pll */ | ||
117 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
118 | VID_PLL_BYPASS, VID_PLL_BYPASS); | ||
119 | /* Enable the vid_pll output clock */ | ||
120 | regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, | ||
121 | VID_PLL_EN, VID_PLL_EN); | ||
122 | 275 | ||
123 | /* Setup the VCLK2 divider value to achieve 27MHz */ | 276 | /* Setup the VCLK2 divider value to achieve 27MHz */ |
124 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV, | 277 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV, |
@@ -159,9 +312,454 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) | |||
159 | CTS_VDAC_EN, CTS_VDAC_EN); | 312 | CTS_VDAC_EN, CTS_VDAC_EN); |
160 | } | 313 | } |
161 | 314 | ||
315 | |||
316 | /* PLL O1 O2 O3 VP DV EN TX */ | ||
317 | /* 4320 /4 /4 /1 /5 /1 => /2 /2 */ | ||
318 | #define MESON_VCLK_HDMI_ENCI_54000 1 | ||
319 | /* 4320 /4 /4 /1 /5 /1 => /1 /2 */ | ||
320 | #define MESON_VCLK_HDMI_DDR_54000 2 | ||
321 | /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ | ||
322 | #define MESON_VCLK_HDMI_DDR_148500 3 | ||
323 | /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ | ||
324 | #define MESON_VCLK_HDMI_74250 4 | ||
325 | /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ | ||
326 | #define MESON_VCLK_HDMI_148500 5 | ||
327 | /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ | ||
328 | #define MESON_VCLK_HDMI_297000 6 | ||
329 | /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ | ||
330 | #define MESON_VCLK_HDMI_594000 7 | ||
331 | |||
332 | struct meson_vclk_params { | ||
333 | unsigned int pll_base_freq; | ||
334 | unsigned int pll_od1; | ||
335 | unsigned int pll_od2; | ||
336 | unsigned int pll_od3; | ||
337 | unsigned int vid_pll_div; | ||
338 | unsigned int vclk_div; | ||
339 | } params[] = { | ||
340 | [MESON_VCLK_HDMI_ENCI_54000] = { | ||
341 | .pll_base_freq = 4320000, | ||
342 | .pll_od1 = 4, | ||
343 | .pll_od2 = 4, | ||
344 | .pll_od3 = 1, | ||
345 | .vid_pll_div = VID_PLL_DIV_5, | ||
346 | .vclk_div = 1, | ||
347 | }, | ||
348 | [MESON_VCLK_HDMI_DDR_54000] = { | ||
349 | .pll_base_freq = 4320000, | ||
350 | .pll_od1 = 4, | ||
351 | .pll_od2 = 4, | ||
352 | .pll_od3 = 1, | ||
353 | .vid_pll_div = VID_PLL_DIV_5, | ||
354 | .vclk_div = 1, | ||
355 | }, | ||
356 | [MESON_VCLK_HDMI_DDR_148500] = { | ||
357 | .pll_base_freq = 2970000, | ||
358 | .pll_od1 = 4, | ||
359 | .pll_od2 = 1, | ||
360 | .pll_od3 = 1, | ||
361 | .vid_pll_div = VID_PLL_DIV_5, | ||
362 | .vclk_div = 1, | ||
363 | }, | ||
364 | [MESON_VCLK_HDMI_74250] = { | ||
365 | .pll_base_freq = 2970000, | ||
366 | .pll_od1 = 2, | ||
367 | .pll_od2 = 2, | ||
368 | .pll_od3 = 2, | ||
369 | .vid_pll_div = VID_PLL_DIV_5, | ||
370 | .vclk_div = 1, | ||
371 | }, | ||
372 | [MESON_VCLK_HDMI_148500] = { | ||
373 | .pll_base_freq = 2970000, | ||
374 | .pll_od1 = 1, | ||
375 | .pll_od2 = 2, | ||
376 | .pll_od3 = 2, | ||
377 | .vid_pll_div = VID_PLL_DIV_5, | ||
378 | .vclk_div = 1, | ||
379 | }, | ||
380 | [MESON_VCLK_HDMI_297000] = { | ||
381 | .pll_base_freq = 2970000, | ||
382 | .pll_od1 = 1, | ||
383 | .pll_od2 = 1, | ||
384 | .pll_od3 = 1, | ||
385 | .vid_pll_div = VID_PLL_DIV_5, | ||
386 | .vclk_div = 2, | ||
387 | }, | ||
388 | [MESON_VCLK_HDMI_594000] = { | ||
389 | .pll_base_freq = 5940000, | ||
390 | .pll_od1 = 1, | ||
391 | .pll_od2 = 1, | ||
392 | .pll_od3 = 2, | ||
393 | .vid_pll_div = VID_PLL_DIV_5, | ||
394 | .vclk_div = 1, | ||
395 | }, | ||
396 | }; | ||
397 | |||
398 | static inline unsigned int pll_od_to_reg(unsigned int od) | ||
399 | { | ||
400 | switch (od) { | ||
401 | case 1: | ||
402 | return 0; | ||
403 | case 2: | ||
404 | return 1; | ||
405 | case 4: | ||
406 | return 2; | ||
407 | case 8: | ||
408 | return 3; | ||
409 | } | ||
410 | |||
411 | /* Invalid */ | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | void meson_hdmi_pll_set(struct meson_drm *priv, | ||
416 | unsigned int base, | ||
417 | unsigned int od1, | ||
418 | unsigned int od2, | ||
419 | unsigned int od3) | ||
420 | { | ||
421 | unsigned int val; | ||
422 | |||
423 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { | ||
424 | switch (base) { | ||
425 | case 2970000: | ||
426 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); | ||
427 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
428 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); | ||
429 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
430 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
431 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
432 | |||
433 | /* Enable and unreset */ | ||
434 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
435 | 0x7 << 28, 0x4 << 28); | ||
436 | |||
437 | /* Poll for lock bit */ | ||
438 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
439 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
440 | |||
441 | /* div_frac */ | ||
442 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
443 | 0xFFFF, 0x4e00); | ||
444 | break; | ||
445 | |||
446 | case 4320000: | ||
447 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); | ||
448 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
449 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); | ||
450 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
451 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
452 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
453 | |||
454 | /* unreset */ | ||
455 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
456 | BIT(28), 0); | ||
457 | |||
458 | /* Poll for lock bit */ | ||
459 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
460 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
461 | break; | ||
462 | |||
463 | case 5940000: | ||
464 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b); | ||
465 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
466 | 0xFFFF, 0x4c00); | ||
467 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); | ||
468 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
469 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
470 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
471 | |||
472 | /* unreset */ | ||
473 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
474 | BIT(28), 0); | ||
475 | |||
476 | /* Poll for lock bit */ | ||
477 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
478 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
479 | break; | ||
480 | }; | ||
481 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | ||
482 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { | ||
483 | switch (base) { | ||
484 | case 2970000: | ||
485 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); | ||
486 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); | ||
487 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
488 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
489 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
490 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
491 | break; | ||
492 | |||
493 | case 4320000: | ||
494 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); | ||
495 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); | ||
496 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
497 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
498 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
499 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
500 | break; | ||
501 | |||
502 | case 5940000: | ||
503 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7); | ||
504 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200); | ||
505 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
506 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
507 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
508 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
509 | break; | ||
510 | |||
511 | }; | ||
512 | |||
513 | /* Reset PLL */ | ||
514 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
515 | HDMI_PLL_RESET, HDMI_PLL_RESET); | ||
516 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
517 | HDMI_PLL_RESET, 0); | ||
518 | |||
519 | /* Poll for lock bit */ | ||
520 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, | ||
521 | (val & HDMI_PLL_LOCK), 10, 0); | ||
522 | }; | ||
523 | |||
524 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | ||
525 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
526 | 3 << 16, pll_od_to_reg(od1) << 16); | ||
527 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | ||
528 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | ||
529 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, | ||
530 | 3 << 21, pll_od_to_reg(od1) << 21); | ||
531 | |||
532 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | ||
533 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
534 | 3 << 22, pll_od_to_reg(od2) << 22); | ||
535 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | ||
536 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | ||
537 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, | ||
538 | 3 << 23, pll_od_to_reg(od2) << 23); | ||
539 | |||
540 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | ||
541 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
542 | 3 << 18, pll_od_to_reg(od3) << 18); | ||
543 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | ||
544 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | ||
545 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, | ||
546 | 3 << 19, pll_od_to_reg(od3) << 19); | ||
547 | } | ||
548 | |||
162 | void meson_vclk_setup(struct meson_drm *priv, unsigned int target, | 549 | void meson_vclk_setup(struct meson_drm *priv, unsigned int target, |
163 | unsigned int freq) | 550 | unsigned int vclk_freq, unsigned int venc_freq, |
551 | unsigned int dac_freq, bool hdmi_use_enci) | ||
164 | { | 552 | { |
165 | if (target == MESON_VCLK_TARGET_CVBS && freq == MESON_VCLK_CVBS) | 553 | unsigned int freq; |
554 | unsigned int hdmi_tx_div; | ||
555 | unsigned int venc_div; | ||
556 | |||
557 | if (target == MESON_VCLK_TARGET_CVBS) { | ||
166 | meson_venci_cvbs_clock_config(priv); | 558 | meson_venci_cvbs_clock_config(priv); |
559 | return; | ||
560 | } | ||
561 | |||
562 | hdmi_tx_div = vclk_freq / dac_freq; | ||
563 | |||
564 | if (hdmi_tx_div == 0) { | ||
565 | pr_err("Fatal Error, invalid HDMI-TX freq %d\n", | ||
566 | dac_freq); | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | venc_div = vclk_freq / venc_freq; | ||
571 | |||
572 | if (venc_div == 0) { | ||
573 | pr_err("Fatal Error, invalid HDMI venc freq %d\n", | ||
574 | venc_freq); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | switch (vclk_freq) { | ||
579 | case 54000: | ||
580 | if (hdmi_use_enci) | ||
581 | freq = MESON_VCLK_HDMI_ENCI_54000; | ||
582 | else | ||
583 | freq = MESON_VCLK_HDMI_DDR_54000; | ||
584 | break; | ||
585 | case 74250: | ||
586 | freq = MESON_VCLK_HDMI_74250; | ||
587 | break; | ||
588 | case 148500: | ||
589 | if (dac_freq != 148500) | ||
590 | freq = MESON_VCLK_HDMI_DDR_148500; | ||
591 | else | ||
592 | freq = MESON_VCLK_HDMI_148500; | ||
593 | break; | ||
594 | case 297000: | ||
595 | freq = MESON_VCLK_HDMI_297000; | ||
596 | break; | ||
597 | case 594000: | ||
598 | freq = MESON_VCLK_HDMI_594000; | ||
599 | break; | ||
600 | default: | ||
601 | pr_err("Fatal Error, invalid HDMI vclk freq %d\n", | ||
602 | vclk_freq); | ||
603 | return; | ||
604 | } | ||
605 | |||
606 | /* Set HDMI-TX sys clock */ | ||
607 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
608 | CTS_HDMI_SYS_SEL_MASK, 0); | ||
609 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
610 | CTS_HDMI_SYS_DIV_MASK, 0); | ||
611 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
612 | CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); | ||
613 | |||
614 | /* Set HDMI PLL rate */ | ||
615 | meson_hdmi_pll_set(priv, params[freq].pll_base_freq, | ||
616 | params[freq].pll_od1, | ||
617 | params[freq].pll_od2, | ||
618 | params[freq].pll_od3); | ||
619 | |||
620 | /* Setup vid_pll divider */ | ||
621 | meson_vid_pll_set(priv, params[freq].vid_pll_div); | ||
622 | |||
623 | /* Set VCLK div */ | ||
624 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
625 | VCLK_SEL_MASK, 0); | ||
626 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
627 | VCLK_DIV_MASK, params[freq].vclk_div - 1); | ||
628 | |||
629 | /* Set HDMI-TX source */ | ||
630 | switch (hdmi_tx_div) { | ||
631 | case 1: | ||
632 | /* enable vclk_div1 gate */ | ||
633 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
634 | VCLK_DIV1_EN, VCLK_DIV1_EN); | ||
635 | |||
636 | /* select vclk_div1 for HDMI-TX */ | ||
637 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
638 | HDMI_TX_PIXEL_SEL_MASK, 0); | ||
639 | break; | ||
640 | case 2: | ||
641 | /* enable vclk_div2 gate */ | ||
642 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
643 | VCLK_DIV2_EN, VCLK_DIV2_EN); | ||
644 | |||
645 | /* select vclk_div2 for HDMI-TX */ | ||
646 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
647 | HDMI_TX_PIXEL_SEL_MASK, 1 << HDMI_TX_PIXEL_SEL_SHIFT); | ||
648 | break; | ||
649 | case 4: | ||
650 | /* enable vclk_div4 gate */ | ||
651 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
652 | VCLK_DIV4_EN, VCLK_DIV4_EN); | ||
653 | |||
654 | /* select vclk_div4 for HDMI-TX */ | ||
655 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
656 | HDMI_TX_PIXEL_SEL_MASK, 2 << HDMI_TX_PIXEL_SEL_SHIFT); | ||
657 | break; | ||
658 | case 6: | ||
659 | /* enable vclk_div6 gate */ | ||
660 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
661 | VCLK_DIV6_EN, VCLK_DIV6_EN); | ||
662 | |||
663 | /* select vclk_div6 for HDMI-TX */ | ||
664 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
665 | HDMI_TX_PIXEL_SEL_MASK, 3 << HDMI_TX_PIXEL_SEL_SHIFT); | ||
666 | break; | ||
667 | case 12: | ||
668 | /* enable vclk_div12 gate */ | ||
669 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
670 | VCLK_DIV12_EN, VCLK_DIV12_EN); | ||
671 | |||
672 | /* select vclk_div12 for HDMI-TX */ | ||
673 | regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, | ||
674 | HDMI_TX_PIXEL_SEL_MASK, 4 << HDMI_TX_PIXEL_SEL_SHIFT); | ||
675 | break; | ||
676 | } | ||
677 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, | ||
678 | HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN); | ||
679 | |||
680 | /* Set ENCI/ENCP Source */ | ||
681 | switch (venc_div) { | ||
682 | case 1: | ||
683 | /* enable vclk_div1 gate */ | ||
684 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
685 | VCLK_DIV1_EN, VCLK_DIV1_EN); | ||
686 | |||
687 | if (hdmi_use_enci) | ||
688 | /* select vclk_div1 for enci */ | ||
689 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
690 | CTS_ENCI_SEL_MASK, 0); | ||
691 | else | ||
692 | /* select vclk_div1 for encp */ | ||
693 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
694 | CTS_ENCP_SEL_MASK, 0); | ||
695 | break; | ||
696 | case 2: | ||
697 | /* enable vclk_div2 gate */ | ||
698 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
699 | VCLK_DIV2_EN, VCLK_DIV2_EN); | ||
700 | |||
701 | if (hdmi_use_enci) | ||
702 | /* select vclk_div2 for enci */ | ||
703 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
704 | CTS_ENCI_SEL_MASK, 1 << CTS_ENCI_SEL_SHIFT); | ||
705 | else | ||
706 | /* select vclk_div2 for encp */ | ||
707 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
708 | CTS_ENCP_SEL_MASK, 1 << CTS_ENCP_SEL_SHIFT); | ||
709 | break; | ||
710 | case 4: | ||
711 | /* enable vclk_div4 gate */ | ||
712 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
713 | VCLK_DIV4_EN, VCLK_DIV4_EN); | ||
714 | |||
715 | if (hdmi_use_enci) | ||
716 | /* select vclk_div4 for enci */ | ||
717 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
718 | CTS_ENCI_SEL_MASK, 2 << CTS_ENCI_SEL_SHIFT); | ||
719 | else | ||
720 | /* select vclk_div4 for encp */ | ||
721 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
722 | CTS_ENCP_SEL_MASK, 2 << CTS_ENCP_SEL_SHIFT); | ||
723 | break; | ||
724 | case 6: | ||
725 | /* enable vclk_div6 gate */ | ||
726 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
727 | VCLK_DIV6_EN, VCLK_DIV6_EN); | ||
728 | |||
729 | if (hdmi_use_enci) | ||
730 | /* select vclk_div6 for enci */ | ||
731 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
732 | CTS_ENCI_SEL_MASK, 3 << CTS_ENCI_SEL_SHIFT); | ||
733 | else | ||
734 | /* select vclk_div6 for encp */ | ||
735 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
736 | CTS_ENCP_SEL_MASK, 3 << CTS_ENCP_SEL_SHIFT); | ||
737 | break; | ||
738 | case 12: | ||
739 | /* enable vclk_div12 gate */ | ||
740 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, | ||
741 | VCLK_DIV12_EN, VCLK_DIV12_EN); | ||
742 | |||
743 | if (hdmi_use_enci) | ||
744 | /* select vclk_div12 for enci */ | ||
745 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
746 | CTS_ENCI_SEL_MASK, 4 << CTS_ENCI_SEL_SHIFT); | ||
747 | else | ||
748 | /* select vclk_div12 for encp */ | ||
749 | regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, | ||
750 | CTS_ENCP_SEL_MASK, 4 << CTS_ENCP_SEL_SHIFT); | ||
751 | break; | ||
752 | } | ||
753 | |||
754 | if (hdmi_use_enci) | ||
755 | /* Enable ENCI clock gate */ | ||
756 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, | ||
757 | CTS_ENCI_EN, CTS_ENCI_EN); | ||
758 | else | ||
759 | /* Enable ENCP clock gate */ | ||
760 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2, | ||
761 | CTS_ENCP_EN, CTS_ENCP_EN); | ||
762 | |||
763 | regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN); | ||
167 | } | 764 | } |
765 | EXPORT_SYMBOL_GPL(meson_vclk_setup); | ||
diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index ec62735996de..0401b5213471 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h | |||
@@ -23,12 +23,14 @@ | |||
23 | 23 | ||
24 | enum { | 24 | enum { |
25 | MESON_VCLK_TARGET_CVBS = 0, | 25 | MESON_VCLK_TARGET_CVBS = 0, |
26 | MESON_VCLK_TARGET_HDMI = 1, | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | /* 27MHz is the CVBS Pixel Clock */ | 29 | /* 27MHz is the CVBS Pixel Clock */ |
29 | #define MESON_VCLK_CVBS 27000 | 30 | #define MESON_VCLK_CVBS 27000 |
30 | 31 | ||
31 | void meson_vclk_setup(struct meson_drm *priv, unsigned int target, | 32 | void meson_vclk_setup(struct meson_drm *priv, unsigned int target, |
32 | unsigned int freq); | 33 | unsigned int vclk_freq, unsigned int venc_freq, |
34 | unsigned int dac_freq, bool hdmi_use_enci); | ||
33 | 35 | ||
34 | #endif /* __MESON_VCLK_H */ | 36 | #endif /* __MESON_VCLK_H */ |
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index a96fcb40f2c7..5d4f19ac98fc 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c | |||
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | #include "meson_venc_cvbs.h" | 33 | #include "meson_venc_cvbs.h" |
34 | #include "meson_venc.h" | 34 | #include "meson_venc.h" |
35 | #include "meson_vclk.h" | ||
35 | #include "meson_registers.h" | 36 | #include "meson_registers.h" |
36 | 37 | ||
37 | /* HHI VDAC Registers */ | 38 | /* HHI VDAC Registers */ |
@@ -194,14 +195,20 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, | |||
194 | { | 195 | { |
195 | struct meson_venc_cvbs *meson_venc_cvbs = | 196 | struct meson_venc_cvbs *meson_venc_cvbs = |
196 | encoder_to_meson_venc_cvbs(encoder); | 197 | encoder_to_meson_venc_cvbs(encoder); |
198 | struct meson_drm *priv = meson_venc_cvbs->priv; | ||
197 | int i; | 199 | int i; |
198 | 200 | ||
199 | for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) { | 201 | for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) { |
200 | struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i]; | 202 | struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i]; |
201 | 203 | ||
202 | if (drm_mode_equal(mode, &meson_mode->mode)) { | 204 | if (drm_mode_equal(mode, &meson_mode->mode)) { |
203 | meson_venci_cvbs_mode_set(meson_venc_cvbs->priv, | 205 | meson_venci_cvbs_mode_set(priv, |
204 | meson_mode->enci); | 206 | meson_mode->enci); |
207 | |||
208 | /* Setup 27MHz vclk2 for ENCI and VDAC */ | ||
209 | meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, | ||
210 | MESON_VCLK_CVBS, MESON_VCLK_CVBS, | ||
211 | MESON_VCLK_CVBS, true); | ||
205 | break; | 212 | break; |
206 | } | 213 | } |
207 | } | 214 | } |