d511f1e212a67c2aa69a46163f2335e1bfe5d0af
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0595-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch
1 From d0931317c51f14bf65af65e7c3f2df6bb26d7c97 Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime@cerno.tech>
3 Date: Tue, 17 Dec 2019 11:48:37 +0100
4 Subject: [PATCH] drm/vc4: hdmi: Support the BCM2711 HDMI controllers
5
6 Now that the driver is ready for it, let's bring in the HDMI controllers
7 variants for the BCM2711.
8
9 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
10 ---
11 drivers/gpu/drm/vc4/vc4_hdmi.c | 254 +++++++++++++++
12 drivers/gpu/drm/vc4/vc4_hdmi.h | 35 +++
13 drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 469 ++++++++++++++++++++++++++++
14 drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 201 ++++++++++++
15 4 files changed, 959 insertions(+)
16
17 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
18 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
19 @@ -42,6 +42,7 @@
20 #include <linux/of_platform.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/rational.h>
23 +#include <linux/reset.h>
24 #include <sound/dmaengine_pcm.h>
25 #include <sound/pcm_drm_eld.h>
26 #include <sound/pcm_params.h>
27 @@ -52,6 +53,31 @@
28 #include "vc4_hdmi_regs.h"
29 #include "vc4_regs.h"
30
31 +#define VC5_HDMI_HORZA_HFP_SHIFT 16
32 +#define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16)
33 +#define VC5_HDMI_HORZA_VPOS BIT(15)
34 +#define VC5_HDMI_HORZA_HPOS BIT(14)
35 +#define VC5_HDMI_HORZA_HAP_SHIFT 0
36 +#define VC5_HDMI_HORZA_HAP_MASK VC4_MASK(13, 0)
37 +
38 +#define VC5_HDMI_HORZB_HBP_SHIFT 16
39 +#define VC5_HDMI_HORZB_HBP_MASK VC4_MASK(26, 16)
40 +#define VC5_HDMI_HORZB_HSP_SHIFT 0
41 +#define VC5_HDMI_HORZB_HSP_MASK VC4_MASK(10, 0)
42 +
43 +#define VC5_HDMI_VERTA_VSP_SHIFT 24
44 +#define VC5_HDMI_VERTA_VSP_MASK VC4_MASK(28, 24)
45 +#define VC5_HDMI_VERTA_VFP_SHIFT 16
46 +#define VC5_HDMI_VERTA_VFP_MASK VC4_MASK(22, 16)
47 +#define VC5_HDMI_VERTA_VAL_SHIFT 0
48 +#define VC5_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0)
49 +
50 +#define VC5_HDMI_VERTB_VSPO_SHIFT 16
51 +#define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)
52 +
53 +# define VC4_HD_M_SW_RST BIT(2)
54 +# define VC4_HD_M_ENABLE BIT(0)
55 +
56 #define CEC_CLOCK_FREQ 40000
57
58 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
59 @@ -75,6 +101,13 @@ static void vc4_hdmi_reset(struct vc4_hd
60 HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
61 }
62
63 +static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
64 +{
65 + reset_control_reset(vc4_hdmi->reset);
66 +
67 + HDMI_WRITE(HDMI_DVP_CTL, 0);
68 +}
69 +
70 static enum drm_connector_status
71 vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
72 {
73 @@ -371,6 +404,45 @@ static void vc4_hdmi_csc_setup(struct vc
74 HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
75 }
76
77 +static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
78 +{
79 + u32 csc_ctl;
80 +
81 + csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */
82 +
83 + if (enable) {
84 + /* CEA VICs other than #1 requre limited range RGB
85 + * output unless overridden by an AVI infoframe.
86 + * Apply a colorspace conversion to squash 0-255 down
87 + * to 16-235. The matrix here is:
88 + *
89 + * [ 0.8594 0 0 16]
90 + * [ 0 0.8594 0 16]
91 + * [ 0 0 0.8594 16]
92 + * [ 0 0 0 1]
93 + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
94 + */
95 + HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80);
96 + HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000);
97 + HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000);
98 + HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000);
99 + HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000);
100 + HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80);
101 + } else {
102 + /* Still use the matrix for full range, but make it unity.
103 + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
104 + */
105 + HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000);
106 + HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000);
107 + HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000);
108 + HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000);
109 + HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000);
110 + HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000);
111 + }
112 +
113 + HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
114 +}
115 +
116 static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
117 struct drm_display_mode *mode)
118 {
119 @@ -420,6 +492,58 @@ static void vc4_hdmi_set_timings(struct
120 (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
121 }
122
123 +static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
124 + struct drm_display_mode *mode)
125 +{
126 + bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
127 + bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
128 + bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
129 + u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
130 + u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
131 + VC5_HDMI_VERTA_VSP) |
132 + VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
133 + VC5_HDMI_VERTA_VFP) |
134 + VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
135 + u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
136 + VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
137 + VC4_HDMI_VERTB_VBP));
138 + u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
139 + VC4_SET_FIELD(mode->crtc_vtotal -
140 + mode->crtc_vsync_end -
141 + interlaced,
142 + VC4_HDMI_VERTB_VBP));
143 +
144 + HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
145 + HDMI_WRITE(HDMI_HORZA,
146 + (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) |
147 + (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) |
148 + VC4_SET_FIELD(mode->hdisplay * pixel_rep,
149 + VC5_HDMI_HORZA_HAP) |
150 + VC4_SET_FIELD((mode->hsync_start -
151 + mode->hdisplay) * pixel_rep,
152 + VC5_HDMI_HORZA_HFP));
153 +
154 + HDMI_WRITE(HDMI_HORZB,
155 + VC4_SET_FIELD((mode->htotal -
156 + mode->hsync_end) * pixel_rep,
157 + VC5_HDMI_HORZB_HBP) |
158 + VC4_SET_FIELD((mode->hsync_end -
159 + mode->hsync_start) * pixel_rep,
160 + VC5_HDMI_HORZB_HSP));
161 +
162 + HDMI_WRITE(HDMI_VERTA0, verta);
163 + HDMI_WRITE(HDMI_VERTA1, verta);
164 +
165 + HDMI_WRITE(HDMI_VERTB0, vertb_even);
166 + HDMI_WRITE(HDMI_VERTB1, vertb);
167 +
168 + HDMI_WRITE(HDMI_VID_CTL,
169 + (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
170 + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
171 +
172 + HDMI_WRITE(HDMI_CLOCK_STOP, 0);
173 +}
174 +
175 static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
176 {
177 struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
178 @@ -1336,6 +1460,92 @@ static int vc4_hdmi_init_resources(struc
179 return 0;
180 }
181
182 +static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
183 +{
184 + struct platform_device *pdev = vc4_hdmi->pdev;
185 + struct device *dev = &pdev->dev;
186 + struct resource *res;
187 +
188 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
189 + if (!res)
190 + return -ENODEV;
191 +
192 + vc4_hdmi->hdmicore_regs = devm_ioremap(dev, res->start,
193 + resource_size(res));
194 + if (IS_ERR(vc4_hdmi->hdmicore_regs))
195 + return PTR_ERR(vc4_hdmi->hdmicore_regs);
196 +
197 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hd");
198 + if (!res)
199 + return -ENODEV;
200 +
201 + vc4_hdmi->hd_regs = devm_ioremap(dev, res->start, resource_size(res));
202 + if (IS_ERR(vc4_hdmi->hd_regs))
203 + return PTR_ERR(vc4_hdmi->hd_regs);
204 +
205 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cec");
206 + if (!res)
207 + return -ENODEV;
208 +
209 + vc4_hdmi->cec_regs = devm_ioremap(dev, res->start, resource_size(res));
210 + if (IS_ERR(vc4_hdmi->cec_regs))
211 + return PTR_ERR(vc4_hdmi->cec_regs);
212 +
213 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csc");
214 + if (!res)
215 + return -ENODEV;
216 +
217 + vc4_hdmi->csc_regs = devm_ioremap(dev, res->start, resource_size(res));
218 + if (IS_ERR(vc4_hdmi->csc_regs))
219 + return PTR_ERR(vc4_hdmi->csc_regs);
220 +
221 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvp");
222 + if (!res)
223 + return -ENODEV;
224 +
225 + vc4_hdmi->dvp_regs = devm_ioremap(dev, res->start, resource_size(res));
226 + if (IS_ERR(vc4_hdmi->dvp_regs))
227 + return PTR_ERR(vc4_hdmi->dvp_regs);
228 +
229 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
230 + if (!res)
231 + return -ENODEV;
232 +
233 + vc4_hdmi->phy_regs = devm_ioremap(dev, res->start, resource_size(res));
234 + if (IS_ERR(vc4_hdmi->phy_regs))
235 + return PTR_ERR(vc4_hdmi->phy_regs);
236 +
237 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "packet");
238 + if (!res)
239 + return -ENODEV;
240 +
241 + vc4_hdmi->ram_regs = devm_ioremap(dev, res->start, resource_size(res));
242 + if (IS_ERR(vc4_hdmi->ram_regs))
243 + return PTR_ERR(vc4_hdmi->ram_regs);
244 +
245 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rm");
246 + if (!res)
247 + return -ENODEV;
248 +
249 + vc4_hdmi->rm_regs = devm_ioremap(dev, res->start, resource_size(res));
250 + if (IS_ERR(vc4_hdmi->rm_regs))
251 + return PTR_ERR(vc4_hdmi->rm_regs);
252 +
253 + vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
254 + if (IS_ERR(vc4_hdmi->hsm_clock)) {
255 + DRM_ERROR("Failed to get HDMI state machine clock\n");
256 + return PTR_ERR(vc4_hdmi->hsm_clock);
257 + }
258 +
259 + vc4_hdmi->reset = devm_reset_control_get(dev, NULL);
260 + if (IS_ERR(vc4_hdmi->reset)) {
261 + DRM_ERROR("Failed to get HDMI reset line\n");
262 + return PTR_ERR(vc4_hdmi->reset);
263 + }
264 +
265 + return 0;
266 +}
267 +
268 static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
269 {
270 struct platform_device *pdev = to_platform_device(dev);
271 @@ -1491,8 +1701,52 @@ static const struct vc4_hdmi_variant bcm
272 .phy_rng_disable = vc4_hdmi_phy_rng_disable,
273 };
274
275 +static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
276 + .id = 0,
277 + .max_pixel_clock = 297000000,
278 + .registers = vc5_hdmi_hdmi0_fields,
279 + .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
280 + .phy_lane_mapping = {
281 + PHY_LANE_0,
282 + PHY_LANE_1,
283 + PHY_LANE_2,
284 + PHY_LANE_CK,
285 + },
286 +
287 + .init_resources = vc5_hdmi_init_resources,
288 + .csc_setup = vc5_hdmi_csc_setup,
289 + .reset = vc5_hdmi_reset,
290 + .set_timings = vc5_hdmi_set_timings,
291 + .phy_init = vc5_hdmi_phy_init,
292 + .phy_rng_enable = vc5_hdmi_phy_rng_enable,
293 + .phy_rng_disable = vc5_hdmi_phy_rng_disable,
294 +};
295 +
296 +static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
297 + .id = 1,
298 + .max_pixel_clock = 297000000,
299 + .registers = vc5_hdmi_hdmi1_fields,
300 + .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
301 + .phy_lane_mapping = {
302 + PHY_LANE_1,
303 + PHY_LANE_0,
304 + PHY_LANE_CK,
305 + PHY_LANE_2,
306 + },
307 +
308 + .init_resources = vc5_hdmi_init_resources,
309 + .csc_setup = vc5_hdmi_csc_setup,
310 + .reset = vc5_hdmi_reset,
311 + .set_timings = vc5_hdmi_set_timings,
312 + .phy_init = vc5_hdmi_phy_init,
313 + .phy_rng_enable = vc5_hdmi_phy_rng_enable,
314 + .phy_rng_disable = vc5_hdmi_phy_rng_disable,
315 +};
316 +
317 static const struct of_device_id vc4_hdmi_dt_match[] = {
318 { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant },
319 + { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant },
320 + { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant },
321 {}
322 };
323
324 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h
325 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
326 @@ -26,6 +26,13 @@ struct drm_display_mode;
327 struct vc4_hdmi;
328 struct vc4_hdmi_register;
329
330 +enum vc4_hdmi_phy_channel {
331 + PHY_LANE_0 = 0,
332 + PHY_LANE_1,
333 + PHY_LANE_2,
334 + PHY_LANE_CK,
335 +};
336 +
337 struct vc4_hdmi_variant {
338 /* On devices that have multiple, different instances (like
339 * the BCM2711), which instance is that variant useful for.
340 @@ -47,6 +54,13 @@ struct vc4_hdmi_variant {
341 /* Number of registers on that variant */
342 unsigned int num_registers;
343
344 + /* BCM2711 Only.
345 + * The variants don't map the lane in the same order in the
346 + * PHY, so this is an array mapping the HDMI channel (index)
347 + * to the PHY lane (value).
348 + */
349 + enum vc4_hdmi_phy_channel phy_lane_mapping[4];
350 +
351 /* Callback to get the resources (memory region, interrupts,
352 * clocks, etc) for that variant.
353 */
354 @@ -102,6 +116,20 @@ struct vc4_hdmi {
355 struct i2c_adapter *ddc;
356 void __iomem *hdmicore_regs;
357 void __iomem *hd_regs;
358 +
359 + /* VC5 Only */
360 + void __iomem *cec_regs;
361 + /* VC5 Only */
362 + void __iomem *csc_regs;
363 + /* VC5 Only */
364 + void __iomem *dvp_regs;
365 + /* VC5 Only */
366 + void __iomem *phy_regs;
367 + /* VC5 Only */
368 + void __iomem *ram_regs;
369 + /* VC5 Only */
370 + void __iomem *rm_regs;
371 +
372 int hpd_gpio;
373 bool hpd_active_low;
374
375 @@ -113,6 +141,8 @@ struct vc4_hdmi {
376 struct clk *pixel_clock;
377 struct clk *hsm_clock;
378
379 + struct reset_control *reset;
380 +
381 struct debugfs_regset32 hdmi_regset;
382 struct debugfs_regset32 hd_regset;
383 };
384 @@ -137,4 +167,9 @@ void vc4_hdmi_phy_disable(struct vc4_hdm
385 void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi);
386 void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi);
387
388 +void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
389 + struct drm_display_mode *mode);
390 +void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi);
391 +void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi);
392 +
393 #endif /* _VC4_HDMI_H_ */
394 --- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
395 +++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
396 @@ -10,6 +10,123 @@
397 #include "vc4_regs.h"
398 #include "vc4_hdmi_regs.h"
399
400 +#define VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB BIT(5)
401 +#define VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB BIT(4)
402 +#define VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET BIT(3)
403 +#define VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET BIT(2)
404 +#define VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET BIT(1)
405 +#define VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET BIT(0)
406 +
407 +#define VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN BIT(4)
408 +
409 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_SHIFT 29
410 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_MASK VC4_MASK(31, 29)
411 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_SHIFT 24
412 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_MASK VC4_MASK(28, 24)
413 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_SHIFT 21
414 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_MASK VC4_MASK(23, 21)
415 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_SHIFT 16
416 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_MASK VC4_MASK(20, 16)
417 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_SHIFT 13
418 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_MASK VC4_MASK(15, 13)
419 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_SHIFT 8
420 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_MASK VC4_MASK(12, 8)
421 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_SHIFT 5
422 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_MASK VC4_MASK(7, 5)
423 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_SHIFT 0
424 +#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_MASK VC4_MASK(4, 0)
425 +
426 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_SHIFT 15
427 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_MASK VC4_MASK(19, 15)
428 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_SHIFT 10
429 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_MASK VC4_MASK(14, 10)
430 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_SHIFT 5
431 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_MASK VC4_MASK(9, 5)
432 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_SHIFT 0
433 +#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_MASK VC4_MASK(4, 0)
434 +
435 +#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_SHIFT 16
436 +#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_MASK VC4_MASK(19, 16)
437 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_SHIFT 12
438 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_MASK VC4_MASK(15, 12)
439 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_SHIFT 8
440 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_MASK VC4_MASK(11, 8)
441 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_SHIFT 4
442 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_MASK VC4_MASK(7, 4)
443 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_SHIFT 0
444 +#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_MASK VC4_MASK(3, 0)
445 +
446 +#define VC4_HDMI_TX_PHY_CTL_3_RP_SHIFT 17
447 +#define VC4_HDMI_TX_PHY_CTL_3_RP_MASK VC4_MASK(19, 17)
448 +#define VC4_HDMI_TX_PHY_CTL_3_RZ_SHIFT 12
449 +#define VC4_HDMI_TX_PHY_CTL_3_RZ_MASK VC4_MASK(16, 12)
450 +#define VC4_HDMI_TX_PHY_CTL_3_CP1_SHIFT 10
451 +#define VC4_HDMI_TX_PHY_CTL_3_CP1_MASK VC4_MASK(11, 10)
452 +#define VC4_HDMI_TX_PHY_CTL_3_CP_SHIFT 8
453 +#define VC4_HDMI_TX_PHY_CTL_3_CP_MASK VC4_MASK(9, 8)
454 +#define VC4_HDMI_TX_PHY_CTL_3_CZ_SHIFT 6
455 +#define VC4_HDMI_TX_PHY_CTL_3_CZ_MASK VC4_MASK(7, 6)
456 +#define VC4_HDMI_TX_PHY_CTL_3_ICP_SHIFT 0
457 +#define VC4_HDMI_TX_PHY_CTL_3_ICP_MASK VC4_MASK(5, 0)
458 +
459 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE BIT(13)
460 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_VC_RANGE_EN BIT(12)
461 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_LOW BIT(11)
462 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_HIGH BIT(10)
463 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_SHIFT 9
464 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_MASK VC4_MASK(9, 9)
465 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_FB_DIV2 BIT(8)
466 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_POST_DIV2 BIT(7)
467 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN BIT(6)
468 +#define VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK BIT(5)
469 +
470 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_SHIFT 16
471 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_MASK VC4_MASK(27, 16)
472 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_SHIFT 14
473 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_MASK VC4_MASK(15, 14)
474 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE BIT(13)
475 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_SHIFT 11
476 +#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_MASK VC4_MASK(12, 11)
477 +
478 +#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_SHIFT 8
479 +#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_MASK VC4_MASK(15, 8)
480 +
481 +#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_SHIFT 0
482 +#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_MASK VC4_MASK(3, 0)
483 +
484 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_MASK VC4_MASK(13, 12)
485 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_SHIFT 12
486 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_MASK VC4_MASK(9, 8)
487 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_SHIFT 8
488 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_MASK VC4_MASK(5, 4)
489 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_SHIFT 4
490 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_MASK VC4_MASK(1, 0)
491 +#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_SHIFT 0
492 +
493 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK VC4_MASK(27, 0)
494 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_SHIFT 0
495 +
496 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK VC4_MASK(27, 0)
497 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_SHIFT 0
498 +
499 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_MASK VC4_MASK(31, 16)
500 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_SHIFT 16
501 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_MASK VC4_MASK(15, 0)
502 +#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_SHIFT 0
503 +
504 +#define VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS BIT(19)
505 +#define VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR BIT(17)
506 +#define VC4_HDMI_RM_CONTROL_FREE_RUN BIT(4)
507 +
508 +#define VC4_HDMI_RM_OFFSET_ONLY BIT(31)
509 +#define VC4_HDMI_RM_OFFSET_OFFSET_SHIFT 0
510 +#define VC4_HDMI_RM_OFFSET_OFFSET_MASK VC4_MASK(30, 0)
511 +
512 +#define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24
513 +#define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24)
514 +
515 +#define OSCILLATOR_FREQUENCY 54000000
516 +
517 void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode)
518 {
519 /* PHY should be in reset, like
520 @@ -38,3 +155,355 @@ void vc4_hdmi_phy_rng_disable(struct vc4
521 HDMI_READ(HDMI_TX_PHY_CTL_0) |
522 VC4_HDMI_TX_PHY_RNG_PWRDN);
523 }
524 +
525 +static unsigned long long
526 +phy_get_vco_freq(unsigned long long clock, u8 *vco_sel, u8 *vco_div)
527 +{
528 + unsigned long long vco_freq = clock;
529 + unsigned int _vco_div = 0;
530 + unsigned int _vco_sel = 0;
531 +
532 + while (vco_freq < 3000000000ULL) {
533 + _vco_div++;
534 + vco_freq = clock * _vco_div * 10;
535 + }
536 +
537 + if (vco_freq > 4500000000ULL)
538 + _vco_sel = 1;
539 +
540 + *vco_sel = _vco_sel;
541 + *vco_div = _vco_div;
542 +
543 + return vco_freq;
544 +}
545 +
546 +static u8 phy_get_cp_current(unsigned long vco_freq)
547 +{
548 + if (vco_freq < 3700000000ULL)
549 + return 0x1c;
550 +
551 + return 0xc8;
552 +}
553 +
554 +static u32 phy_get_rm_offset(unsigned long long vco_freq)
555 +{
556 + unsigned long long fref = OSCILLATOR_FREQUENCY;
557 + uint64_t offset = 0;
558 +
559 + /* RM offset is stored as 9.22 format */
560 + offset = vco_freq * 2;
561 + do_div(offset, fref);
562 + offset = offset << 22;
563 + offset >>= 2;
564 +
565 + return offset;
566 +}
567 +
568 +static u8 phy_get_vco_gain(unsigned long long vco_freq)
569 +{
570 + if (vco_freq < 3350000000ULL)
571 + return 0xf;
572 +
573 + if (vco_freq < 3700000000ULL)
574 + return 0xc;
575 +
576 + if (vco_freq < 4050000000ULL)
577 + return 0x6;
578 +
579 + if (vco_freq < 4800000000ULL)
580 + return 0x5;
581 +
582 + if (vco_freq < 5200000000ULL)
583 + return 0x7;
584 +
585 + return 0x2;
586 +}
587 +
588 +struct phy_lane_settings {
589 + struct {
590 + u8 preemphasis;
591 + u8 main_driver;
592 + } amplitude;
593 +
594 + u8 res_sel_data;
595 + u8 term_res_sel_data;
596 +};
597 +
598 +struct phy_settings {
599 + unsigned long long min_rate;
600 + unsigned long long max_rate;
601 + struct phy_lane_settings channel[3];
602 + struct phy_lane_settings clock;
603 +};
604 +
605 +static const struct phy_settings vc5_hdmi_phy_settings[] =
606 +{
607 + {
608 + 0, 50000000,
609 + {
610 + {{0x0, 0x0A}, 0x12, 0x0},
611 + {{0x0, 0x0A}, 0x12, 0x0},
612 + {{0x0, 0x0A}, 0x12, 0x0}
613 + },
614 + {{0x0, 0x0A}, 0x18, 0x0},
615 + },
616 + {
617 + 50000001, 75000000,
618 + {
619 + {{0x0, 0x09}, 0x12, 0x0},
620 + {{0x0, 0x09}, 0x12, 0x0},
621 + {{0x0, 0x09}, 0x12, 0x0}
622 + },
623 + {{0x0, 0x0C}, 0x18, 0x3},
624 + },
625 + {
626 + 75000001, 165000000,
627 + {
628 + {{0x0, 0x09}, 0x12, 0x0},
629 + {{0x0, 0x09}, 0x12, 0x0},
630 + {{0x0, 0x09}, 0x12, 0x0}
631 + },
632 + {{0x0, 0x0C}, 0x18, 0x3},
633 + },
634 + {
635 + 165000001, 250000000,
636 + {
637 + {{0x0, 0x0F}, 0x12, 0x1},
638 + {{0x0, 0x0F}, 0x12, 0x1},
639 + {{0x0, 0x0F}, 0x12, 0x1}
640 + },
641 + {{0x0, 0x0C}, 0x18, 0x3},
642 + },
643 + {
644 + 250000001, 340000000,
645 + {
646 + {{0x2, 0x0D}, 0x12, 0x1},
647 + {{0x2, 0x0D}, 0x12, 0x1},
648 + {{0x2, 0x0D}, 0x12, 0x1}
649 + },
650 + {{0x0, 0x0C}, 0x18, 0xF},
651 + },
652 + {
653 + 340000001, 450000000,
654 + {
655 + {{0x0, 0x1B}, 0x12, 0xF},
656 + {{0x0, 0x1B}, 0x12, 0xF},
657 + {{0x0, 0x1B}, 0x12, 0xF}
658 + },
659 + {{0x0, 0x0A}, 0x12, 0xF},
660 + },
661 + {
662 + 450000001, 600000000,
663 + {
664 + {{0x0, 0x1C}, 0x12, 0xF},
665 + {{0x0, 0x1C}, 0x12, 0xF},
666 + {{0x0, 0x1C}, 0x12, 0xF}
667 + },
668 + {{0x0, 0x0B}, 0x13, 0xF},
669 + },
670 +};
671 +
672 +static const struct phy_settings *phy_get_settings(unsigned long long tmds_rate)
673 +{
674 + unsigned int count = ARRAY_SIZE(vc5_hdmi_phy_settings);
675 + unsigned int i;
676 +
677 + for (i = 0; i < count; i++) {
678 + const struct phy_settings *s = &vc5_hdmi_phy_settings[i];
679 +
680 + if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate)
681 + return s;
682 + }
683 +
684 + /*
685 + * If the pixel clock exceeds our max setting, try the max
686 + * setting anyway.
687 + */
688 + return &vc5_hdmi_phy_settings[count - 1];
689 +}
690 +
691 +static const struct phy_lane_settings *
692 +phy_get_channel_settings(enum vc4_hdmi_phy_channel chan,
693 + unsigned long long tmds_rate)
694 +{
695 + const struct phy_settings *settings = phy_get_settings(tmds_rate);
696 +
697 + if (chan == PHY_LANE_CK)
698 + return &settings->clock;
699 +
700 + return &settings->channel[chan];
701 +}
702 +
703 +void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode)
704 +{
705 + const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings;
706 + const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
707 + unsigned long long pixel_freq = mode->clock * 1000;
708 + unsigned long long vco_freq;
709 + unsigned char word_sel;
710 + u8 vco_sel, vco_div;
711 +
712 + vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div);
713 +
714 + HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
715 + VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
716 +
717 + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL,
718 + HDMI_READ(HDMI_TX_PHY_RESET_CTL) &
719 + ~VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET &
720 + ~VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET &
721 + ~VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET &
722 + ~VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET);
723 +
724 + HDMI_WRITE(HDMI_RM_CONTROL,
725 + HDMI_READ(HDMI_RM_CONTROL) |
726 + VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS |
727 + VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR |
728 + VC4_HDMI_RM_CONTROL_FREE_RUN);
729 +
730 + HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1,
731 + (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1) &
732 + ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK) |
733 + VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT));
734 +
735 + HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2,
736 + (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2) &
737 + ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK) |
738 + VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT));
739 +
740 + HDMI_WRITE(HDMI_RM_OFFSET,
741 + VC4_SET_FIELD(phy_get_rm_offset(vco_freq),
742 + VC4_HDMI_RM_OFFSET_OFFSET) |
743 + VC4_HDMI_RM_OFFSET_ONLY);
744 +
745 + HDMI_WRITE(HDMI_TX_PHY_CLK_DIV,
746 + VC4_SET_FIELD(vco_div, VC4_HDMI_TX_PHY_CLK_DIV_VCO));
747 +
748 + HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4,
749 + VC4_SET_FIELD(0xe147, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD) |
750 + VC4_SET_FIELD(0xe14, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD));
751 +
752 + HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_0,
753 + VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK |
754 + VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN |
755 + VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE |
756 + VC4_SET_FIELD(vco_sel, VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL));
757 +
758 + HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_1,
759 + HDMI_READ(HDMI_TX_PHY_PLL_CTL_1) |
760 + VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE |
761 + VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL) |
762 + VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY) |
763 + VC4_SET_FIELD(0x8a, VC4_HDMI_TX_PHY_PLL_CTL_1_CPP));
764 +
765 + HDMI_WRITE(HDMI_RM_FORMAT,
766 + HDMI_READ(HDMI_RM_FORMAT) |
767 + VC4_SET_FIELD(2, VC4_HDMI_RM_FORMAT_SHIFT));
768 +
769 + HDMI_WRITE(HDMI_TX_PHY_PLL_CFG,
770 + HDMI_READ(HDMI_TX_PHY_PLL_CFG) |
771 + VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CFG_PDIV));
772 +
773 + if (pixel_freq >= 340000000)
774 + word_sel = 3;
775 + else
776 + word_sel = 0;
777 + HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel);
778 +
779 + HDMI_WRITE(HDMI_TX_PHY_CTL_3,
780 + VC4_SET_FIELD(phy_get_cp_current(vco_freq),
781 + VC4_HDMI_TX_PHY_CTL_3_ICP) |
782 + VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP) |
783 + VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP1) |
784 + VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_CTL_3_CZ) |
785 + VC4_SET_FIELD(4, VC4_HDMI_TX_PHY_CTL_3_RP) |
786 + VC4_SET_FIELD(6, VC4_HDMI_TX_PHY_CTL_3_RZ));
787 +
788 + chan0_settings =
789 + phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_0],
790 + pixel_freq);
791 + chan1_settings =
792 + phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_1],
793 + pixel_freq);
794 + chan2_settings =
795 + phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_2],
796 + pixel_freq);
797 + clock_settings =
798 + phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_CK],
799 + pixel_freq);
800 +
801 + HDMI_WRITE(HDMI_TX_PHY_CTL_0,
802 + VC4_SET_FIELD(chan0_settings->amplitude.preemphasis,
803 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP) |
804 + VC4_SET_FIELD(chan0_settings->amplitude.main_driver,
805 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV) |
806 + VC4_SET_FIELD(chan1_settings->amplitude.preemphasis,
807 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP) |
808 + VC4_SET_FIELD(chan1_settings->amplitude.main_driver,
809 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV) |
810 + VC4_SET_FIELD(chan2_settings->amplitude.preemphasis,
811 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP) |
812 + VC4_SET_FIELD(chan2_settings->amplitude.main_driver,
813 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV) |
814 + VC4_SET_FIELD(clock_settings->amplitude.preemphasis,
815 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP) |
816 + VC4_SET_FIELD(clock_settings->amplitude.main_driver,
817 + VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV));
818 +
819 + HDMI_WRITE(HDMI_TX_PHY_CTL_1,
820 + HDMI_READ(HDMI_TX_PHY_CTL_1) |
821 + VC4_SET_FIELD(chan0_settings->res_sel_data,
822 + VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0) |
823 + VC4_SET_FIELD(chan1_settings->res_sel_data,
824 + VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1) |
825 + VC4_SET_FIELD(chan2_settings->res_sel_data,
826 + VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2) |
827 + VC4_SET_FIELD(clock_settings->res_sel_data,
828 + VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK));
829 +
830 + HDMI_WRITE(HDMI_TX_PHY_CTL_2,
831 + VC4_SET_FIELD(chan0_settings->term_res_sel_data,
832 + VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0) |
833 + VC4_SET_FIELD(chan1_settings->term_res_sel_data,
834 + VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1) |
835 + VC4_SET_FIELD(chan2_settings->term_res_sel_data,
836 + VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2) |
837 + VC4_SET_FIELD(clock_settings->term_res_sel_data,
838 + VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK) |
839 + VC4_SET_FIELD(phy_get_vco_gain(vco_freq),
840 + VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN));
841 +
842 + HDMI_WRITE(HDMI_TX_PHY_CHANNEL_SWAP,
843 + VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_0],
844 + VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL) |
845 + VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_1],
846 + VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL) |
847 + VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_2],
848 + VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL) |
849 + VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_CK],
850 + VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL));
851 +
852 + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL,
853 + HDMI_READ(HDMI_TX_PHY_RESET_CTL) &
854 + ~(VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
855 + VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB));
856 +
857 + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL,
858 + HDMI_READ(HDMI_TX_PHY_RESET_CTL) |
859 + VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
860 + VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB);
861 +}
862 +
863 +void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
864 +{
865 + HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
866 + HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) &
867 + ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
868 +}
869 +
870 +void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
871 +{
872 + HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
873 + HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) |
874 + VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
875 +}
876 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
877 +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
878 @@ -18,6 +18,12 @@ enum vc4_hdmi_regs {
879 VC4_INVALID = 0,
880 VC4_HDMI,
881 VC4_HD,
882 + VC5_CEC,
883 + VC5_CSC,
884 + VC5_DVP,
885 + VC5_PHY,
886 + VC5_RAM,
887 + VC5_RM,
888 };
889
890 enum vc4_hdmi_field {
891 @@ -45,6 +51,7 @@ enum vc4_hdmi_field {
892 HDMI_CEC_TX_DATA_2,
893 HDMI_CEC_TX_DATA_3,
894 HDMI_CEC_TX_DATA_4,
895 + HDMI_CLOCK_STOP,
896 HDMI_CORE_REV,
897 HDMI_CRP_CFG,
898 HDMI_CSC_12_11,
899 @@ -61,6 +68,7 @@ enum vc4_hdmi_field {
900 */
901 HDMI_CTS_0,
902 HDMI_CTS_1,
903 + HDMI_DVP_CTL,
904 HDMI_FIFO_CTL,
905 HDMI_FRAME_COUNT,
906 HDMI_HORZA,
907 @@ -93,10 +101,27 @@ enum vc4_hdmi_field {
908 HDMI_RAM_PACKET_CONFIG,
909 HDMI_RAM_PACKET_START,
910 HDMI_RAM_PACKET_STATUS,
911 + HDMI_RM_CONTROL,
912 + HDMI_RM_FORMAT,
913 + HDMI_RM_OFFSET,
914 HDMI_SCHEDULER_CONTROL,
915 HDMI_SW_RESET_CONTROL,
916 + HDMI_TX_PHY_CHANNEL_SWAP,
917 + HDMI_TX_PHY_CLK_DIV,
918 HDMI_TX_PHY_CTL_0,
919 + HDMI_TX_PHY_CTL_1,
920 + HDMI_TX_PHY_CTL_2,
921 + HDMI_TX_PHY_CTL_3,
922 + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1,
923 + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2,
924 + HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4,
925 + HDMI_TX_PHY_PLL_CFG,
926 + HDMI_TX_PHY_PLL_CTL_0,
927 + HDMI_TX_PHY_PLL_CTL_1,
928 + HDMI_TX_PHY_POWERDOWN_CTL,
929 HDMI_TX_PHY_RESET_CTL,
930 + HDMI_TX_PHY_TMDS_CLK_WORD_SEL,
931 + HDMI_VEC_INTERFACE_XBAR,
932 HDMI_VERTA0,
933 HDMI_VERTA1,
934 HDMI_VERTB0,
935 @@ -119,6 +144,12 @@ struct vc4_hdmi_register {
936
937 #define VC4_HD_REG(reg, offset) _VC4_REG(VC4_HD, reg, offset)
938 #define VC4_HDMI_REG(reg, offset) _VC4_REG(VC4_HDMI, reg, offset)
939 +#define VC5_CEC_REG(reg, offset) _VC4_REG(VC5_CEC, reg, offset)
940 +#define VC5_CSC_REG(reg, offset) _VC4_REG(VC5_CSC, reg, offset)
941 +#define VC5_DVP_REG(reg, offset) _VC4_REG(VC5_DVP, reg, offset)
942 +#define VC5_PHY_REG(reg, offset) _VC4_REG(VC5_PHY, reg, offset)
943 +#define VC5_RAM_REG(reg, offset) _VC4_REG(VC5_RAM, reg, offset)
944 +#define VC5_RM_REG(reg, offset) _VC4_REG(VC5_RM, reg, offset)
945
946 static const struct vc4_hdmi_register vc4_hdmi_fields[] = {
947 VC4_HD_REG(HDMI_M_CTL, 0x000c),
948 @@ -181,6 +212,158 @@ static const struct vc4_hdmi_register vc
949 VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400),
950 };
951
952 +static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = {
953 + VC4_HD_REG(HDMI_DVP_CTL, 0x0000),
954 + VC4_HD_REG(HDMI_MAI_CTL, 0x0010),
955 + VC4_HD_REG(HDMI_MAI_THR, 0x0014),
956 + VC4_HD_REG(HDMI_MAI_FMT, 0x0018),
957 + VC4_HD_REG(HDMI_MAI_DATA, 0x001c),
958 + VC4_HD_REG(HDMI_MAI_SMP, 0x0020),
959 + VC4_HD_REG(HDMI_VID_CTL, 0x0044),
960 + VC4_HD_REG(HDMI_FRAME_COUNT, 0x0060),
961 +
962 + VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074),
963 + VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8),
964 + VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc),
965 + VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4),
966 + VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8),
967 + VC4_HDMI_REG(HDMI_CTS_0, 0x0cc),
968 + VC4_HDMI_REG(HDMI_CTS_1, 0x0d0),
969 + VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0),
970 + VC4_HDMI_REG(HDMI_HORZA, 0x0e4),
971 + VC4_HDMI_REG(HDMI_HORZB, 0x0e8),
972 + VC4_HDMI_REG(HDMI_VERTA0, 0x0ec),
973 + VC4_HDMI_REG(HDMI_VERTB0, 0x0f0),
974 + VC4_HDMI_REG(HDMI_VERTA1, 0x0f4),
975 + VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
976 + VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
977 + VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
978 + VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
979 +
980 + VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
981 + VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
982 +
983 + VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
984 + VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004),
985 + VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008),
986 + VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c),
987 + VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010),
988 + VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014),
989 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c),
990 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020),
991 + VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028),
992 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034),
993 + VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044),
994 + VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c),
995 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050),
996 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054),
997 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c),
998 +
999 + VC5_RM_REG(HDMI_RM_CONTROL, 0x000),
1000 + VC5_RM_REG(HDMI_RM_OFFSET, 0x018),
1001 + VC5_RM_REG(HDMI_RM_FORMAT, 0x01c),
1002 +
1003 + VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000),
1004 +
1005 + VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010),
1006 + VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014),
1007 + VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018),
1008 + VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c),
1009 + VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020),
1010 + VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028),
1011 + VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c),
1012 + VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030),
1013 + VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034),
1014 + VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038),
1015 + VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c),
1016 + VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040),
1017 + VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044),
1018 +
1019 + VC5_CSC_REG(HDMI_CSC_CTL, 0x000),
1020 + VC5_CSC_REG(HDMI_CSC_12_11, 0x004),
1021 + VC5_CSC_REG(HDMI_CSC_14_13, 0x008),
1022 + VC5_CSC_REG(HDMI_CSC_22_21, 0x00c),
1023 + VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
1024 + VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
1025 + VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
1026 +};
1027 +
1028 +static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = {
1029 + VC4_HD_REG(HDMI_DVP_CTL, 0x0000),
1030 + VC4_HD_REG(HDMI_MAI_CTL, 0x0030),
1031 + VC4_HD_REG(HDMI_MAI_THR, 0x0034),
1032 + VC4_HD_REG(HDMI_MAI_FMT, 0x0038),
1033 + VC4_HD_REG(HDMI_MAI_DATA, 0x003c),
1034 + VC4_HD_REG(HDMI_MAI_SMP, 0x0040),
1035 + VC4_HD_REG(HDMI_VID_CTL, 0x0048),
1036 + VC4_HD_REG(HDMI_FRAME_COUNT, 0x0064),
1037 +
1038 + VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074),
1039 + VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8),
1040 + VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc),
1041 + VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4),
1042 + VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8),
1043 + VC4_HDMI_REG(HDMI_CTS_0, 0x0cc),
1044 + VC4_HDMI_REG(HDMI_CTS_1, 0x0d0),
1045 + VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0),
1046 + VC4_HDMI_REG(HDMI_HORZA, 0x0e4),
1047 + VC4_HDMI_REG(HDMI_HORZB, 0x0e8),
1048 + VC4_HDMI_REG(HDMI_VERTA0, 0x0ec),
1049 + VC4_HDMI_REG(HDMI_VERTB0, 0x0f0),
1050 + VC4_HDMI_REG(HDMI_VERTA1, 0x0f4),
1051 + VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
1052 + VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
1053 + VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
1054 + VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
1055 +
1056 + VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
1057 + VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
1058 +
1059 + VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
1060 + VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004),
1061 + VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008),
1062 + VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c),
1063 + VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010),
1064 + VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014),
1065 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c),
1066 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020),
1067 + VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028),
1068 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034),
1069 + VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c),
1070 + VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044),
1071 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050),
1072 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054),
1073 + VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c),
1074 +
1075 + VC5_RM_REG(HDMI_RM_CONTROL, 0x000),
1076 + VC5_RM_REG(HDMI_RM_OFFSET, 0x018),
1077 + VC5_RM_REG(HDMI_RM_FORMAT, 0x01c),
1078 +
1079 + VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000),
1080 +
1081 + VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010),
1082 + VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014),
1083 + VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018),
1084 + VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c),
1085 + VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020),
1086 + VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028),
1087 + VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c),
1088 + VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030),
1089 + VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034),
1090 + VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038),
1091 + VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c),
1092 + VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040),
1093 + VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044),
1094 +
1095 + VC5_CSC_REG(HDMI_CSC_CTL, 0x000),
1096 + VC5_CSC_REG(HDMI_CSC_12_11, 0x004),
1097 + VC5_CSC_REG(HDMI_CSC_14_13, 0x008),
1098 + VC5_CSC_REG(HDMI_CSC_22_21, 0x00c),
1099 + VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
1100 + VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
1101 + VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
1102 +};
1103 +
1104 static inline
1105 void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi,
1106 enum vc4_hdmi_regs reg)
1107 @@ -192,6 +375,24 @@ void __iomem *__vc4_hdmi_get_field_base(
1108 case VC4_HDMI:
1109 return hdmi->hdmicore_regs;
1110
1111 + case VC5_CSC:
1112 + return hdmi->csc_regs;
1113 +
1114 + case VC5_CEC:
1115 + return hdmi->cec_regs;
1116 +
1117 + case VC5_DVP:
1118 + return hdmi->dvp_regs;
1119 +
1120 + case VC5_PHY:
1121 + return hdmi->phy_regs;
1122 +
1123 + case VC5_RAM:
1124 + return hdmi->ram_regs;
1125 +
1126 + case VC5_RM:
1127 + return hdmi->rm_regs;
1128 +
1129 default:
1130 return NULL;
1131 }