1
2
3
4
5
6
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/component.h>
11#include <linux/of_device.h>
12#include <linux/of_graph.h>
13#include <linux/reset.h>
14#include <linux/clk.h>
15#include <linux/regulator/consumer.h>
16
17#include <drm/drmP.h>
18#include <drm/drm_atomic_helper.h>
19#include <drm/drm_edid.h>
20#include <drm/drm_probe_helper.h>
21#include <drm/bridge/dw_hdmi.h>
22
23#include <uapi/linux/media-bus-format.h>
24#include <uapi/linux/videodev2.h>
25
26#include "meson_drv.h"
27#include "meson_venc.h"
28#include "meson_vclk.h"
29#include "meson_dw_hdmi.h"
30#include "meson_registers.h"
31
32#define DRIVER_NAME "meson-dw-hdmi"
33#define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94#define HDMITX_TOP_ADDR_REG 0x0
95#define HDMITX_TOP_DATA_REG 0x4
96#define HDMITX_TOP_CTRL_REG 0x8
97#define HDMITX_TOP_G12A_OFFSET 0x8000
98
99
100#define HDMITX_DWC_ADDR_REG 0x10
101#define HDMITX_DWC_DATA_REG 0x14
102#define HDMITX_DWC_CTRL_REG 0x18
103
104
105#define HHI_MEM_PD_REG0 0x100
106#define HHI_HDMI_CLK_CNTL 0x1cc
107#define HHI_HDMI_PHY_CNTL0 0x3a0
108#define HHI_HDMI_PHY_CNTL1 0x3a4
109#define HHI_HDMI_PHY_CNTL2 0x3a8
110#define HHI_HDMI_PHY_CNTL3 0x3ac
111#define HHI_HDMI_PHY_CNTL4 0x3b0
112#define HHI_HDMI_PHY_CNTL5 0x3b4
113
114static DEFINE_SPINLOCK(reg_lock);
115
116enum meson_venc_source {
117 MESON_VENC_SOURCE_NONE = 0,
118 MESON_VENC_SOURCE_ENCI = 1,
119 MESON_VENC_SOURCE_ENCP = 2,
120};
121
122struct meson_dw_hdmi;
123
124struct meson_dw_hdmi_data {
125 unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi,
126 unsigned int addr);
127 void (*top_write)(struct meson_dw_hdmi *dw_hdmi,
128 unsigned int addr, unsigned int data);
129 unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi,
130 unsigned int addr);
131 void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi,
132 unsigned int addr, unsigned int data);
133};
134
135struct meson_dw_hdmi {
136 struct drm_encoder encoder;
137 struct dw_hdmi_plat_data dw_plat_data;
138 struct meson_drm *priv;
139 struct device *dev;
140 void __iomem *hdmitx;
141 const struct meson_dw_hdmi_data *data;
142 struct reset_control *hdmitx_apb;
143 struct reset_control *hdmitx_ctrl;
144 struct reset_control *hdmitx_phy;
145 struct clk *hdmi_pclk;
146 struct clk *venci_clk;
147 struct regulator *hdmi_supply;
148 u32 irq_stat;
149 struct dw_hdmi *hdmi;
150};
151#define encoder_to_meson_dw_hdmi(x) \
152 container_of(x, struct meson_dw_hdmi, encoder)
153
154static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
155 const char *compat)
156{
157 return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
158}
159
160
161
162static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
163 unsigned int addr)
164{
165 unsigned long flags;
166 unsigned int data;
167
168 spin_lock_irqsave(®_lock, flags);
169
170
171 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
172 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
173
174
175 data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
176 data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
177
178 spin_unlock_irqrestore(®_lock, flags);
179
180 return data;
181}
182
183static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi,
184 unsigned int addr)
185{
186 return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
187}
188
189static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
190 unsigned int addr, unsigned int data)
191{
192 unsigned long flags;
193
194 spin_lock_irqsave(®_lock, flags);
195
196
197 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
198 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
199
200
201 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
202
203 spin_unlock_irqrestore(®_lock, flags);
204}
205
206static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi,
207 unsigned int addr, unsigned int data)
208{
209 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
210}
211
212
213static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
214 unsigned int addr,
215 unsigned int mask,
216 unsigned int val)
217{
218 unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr);
219
220 data &= ~mask;
221 data |= val;
222
223 dw_hdmi->data->top_write(dw_hdmi, addr, data);
224}
225
226static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
227 unsigned int addr)
228{
229 unsigned long flags;
230 unsigned int data;
231
232 spin_lock_irqsave(®_lock, flags);
233
234
235 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
236 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
237
238
239 data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
240 data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
241
242 spin_unlock_irqrestore(®_lock, flags);
243
244 return data;
245}
246
247static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi,
248 unsigned int addr)
249{
250 return readb(dw_hdmi->hdmitx + addr);
251}
252
253static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
254 unsigned int addr, unsigned int data)
255{
256 unsigned long flags;
257
258 spin_lock_irqsave(®_lock, flags);
259
260
261 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
262 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
263
264
265 writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
266
267 spin_unlock_irqrestore(®_lock, flags);
268}
269
270static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi,
271 unsigned int addr, unsigned int data)
272{
273 writeb(data, dw_hdmi->hdmitx + addr);
274}
275
276
277static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
278 unsigned int addr,
279 unsigned int mask,
280 unsigned int val)
281{
282 unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr);
283
284 data &= ~mask;
285 data |= val;
286
287 dw_hdmi->data->dwc_write(dw_hdmi, addr, data);
288}
289
290
291
292
293static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
294 struct drm_display_mode *mode)
295{
296 struct meson_drm *priv = dw_hdmi->priv;
297 unsigned int pixel_clock = mode->clock;
298
299 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
300 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
301 if (pixel_clock >= 371250) {
302
303 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
304 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
305 } else if (pixel_clock >= 297000) {
306
307 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
308 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
309 } else if (pixel_clock >= 148500) {
310
311 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
312 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
313 } else {
314
315 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
316 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
317 }
318 } else if (dw_hdmi_is_compatible(dw_hdmi,
319 "amlogic,meson-gxbb-dw-hdmi")) {
320 if (pixel_clock >= 371250) {
321
322 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
323 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
324 } else if (pixel_clock >= 297000) {
325
326 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
327 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
328 } else {
329
330 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
331 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
332 }
333 } else if (dw_hdmi_is_compatible(dw_hdmi,
334 "amlogic,meson-g12a-dw-hdmi")) {
335 if (pixel_clock >= 371250) {
336
337 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4);
338 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
339 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b);
340 } else if (pixel_clock >= 297000) {
341
342 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262);
343 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
344 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
345 } else {
346
347 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242);
348 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
349 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
350 }
351 }
352}
353
354static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
355{
356 struct meson_drm *priv = dw_hdmi->priv;
357
358
359 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
360
361 mdelay(2);
362
363
364 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
365
366 mdelay(2);
367}
368
369static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
370 struct drm_display_mode *mode)
371{
372 struct meson_drm *priv = dw_hdmi->priv;
373 int vic = drm_match_cea_mode(mode);
374 unsigned int vclk_freq;
375 unsigned int venc_freq;
376 unsigned int hdmi_freq;
377
378 vclk_freq = mode->clock;
379
380 if (!vic) {
381 meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
382 vclk_freq, vclk_freq, false);
383 return;
384 }
385
386 if (mode->flags & DRM_MODE_FLAG_DBLCLK)
387 vclk_freq *= 2;
388
389 venc_freq = vclk_freq;
390 hdmi_freq = vclk_freq;
391
392 if (meson_venc_hdmi_venc_repeat(vic))
393 venc_freq *= 2;
394
395 vclk_freq = max(venc_freq, hdmi_freq);
396
397 if (mode->flags & DRM_MODE_FLAG_DBLCLK)
398 venc_freq /= 2;
399
400 DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
401 vclk_freq, venc_freq, hdmi_freq,
402 priv->venc.hdmi_use_enci);
403
404 meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
405 venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
406}
407
408static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
409 struct drm_display_mode *mode)
410{
411 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
412 struct meson_drm *priv = dw_hdmi->priv;
413 unsigned int wr_clk =
414 readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
415
416 DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name,
417 mode->clock > 340000 ? 40 : 10);
418
419
420 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
421
422
423 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
424
425
426 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
427
428
429 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
430 0x3, 0x3);
431 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
432 0x3 << 4, 0x3 << 4);
433
434
435 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
436
437
438 if (mode->clock > 340000) {
439 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
440 0);
441 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
442 0x03ff03ff);
443 } else {
444 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
445 0x001f001f);
446 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
447 0x001f001f);
448 }
449
450
451 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
452 msleep(20);
453 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
454
455
456 meson_hdmi_phy_setup_mode(dw_hdmi, mode);
457
458
459 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
460 0xffff << 16, 0x0390 << 16);
461
462
463 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
464 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
465 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
466 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
467 BIT(17), 0);
468 else
469 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
470 BIT(17), BIT(17));
471
472
473 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
474
475 dw_hdmi_set_high_tmds_clock_ratio(hdmi);
476
477 msleep(100);
478
479
480 meson_dw_hdmi_phy_reset(dw_hdmi);
481 meson_dw_hdmi_phy_reset(dw_hdmi);
482 meson_dw_hdmi_phy_reset(dw_hdmi);
483
484
485 if (priv->venc.hdmi_use_enci)
486 writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
487 else
488 writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
489
490
491 writel_bits_relaxed(0x3, 0,
492 priv->io_base + _REG(VPU_HDMI_SETTING));
493 writel_bits_relaxed(0xf << 8, 0,
494 priv->io_base + _REG(VPU_HDMI_SETTING));
495
496
497 if (priv->venc.hdmi_use_enci)
498 writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
499 else
500 writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
501
502
503 writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
504 priv->io_base + _REG(VPU_HDMI_SETTING));
505
506
507 if (priv->venc.hdmi_use_enci)
508 writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
509 priv->io_base + _REG(VPU_HDMI_SETTING));
510 else
511 writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
512 priv->io_base + _REG(VPU_HDMI_SETTING));
513
514 return 0;
515}
516
517static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
518 void *data)
519{
520 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
521 struct meson_drm *priv = dw_hdmi->priv;
522
523 DRM_DEBUG_DRIVER("\n");
524
525 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
526}
527
528static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
529 void *data)
530{
531 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
532
533 return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
534 connector_status_connected : connector_status_disconnected;
535}
536
537static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
538 void *data)
539{
540 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
541
542
543 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
544 (0xa << 12) | 0xa0);
545
546
547 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
548 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
549
550
551 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
552 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
553 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
554}
555
556static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
557 .init = dw_hdmi_phy_init,
558 .disable = dw_hdmi_phy_disable,
559 .read_hpd = dw_hdmi_read_hpd,
560 .setup_hpd = dw_hdmi_setup_hpd,
561};
562
563static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
564{
565 struct meson_dw_hdmi *dw_hdmi = dev_id;
566 u32 stat;
567
568 stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
569 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
570
571
572 if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
573 dw_hdmi->irq_stat = stat;
574 return IRQ_WAKE_THREAD;
575 }
576
577
578 if (stat & 1)
579 return IRQ_NONE;
580
581
582
583 return IRQ_HANDLED;
584}
585
586
587static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
588{
589 struct meson_dw_hdmi *dw_hdmi = dev_id;
590 u32 stat = dw_hdmi->irq_stat;
591
592
593 if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
594 bool hpd_connected = false;
595
596 if (stat & HDMITX_TOP_INTR_HPD_RISE)
597 hpd_connected = true;
598
599 dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
600 hpd_connected);
601
602 drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
603 }
604
605 return IRQ_HANDLED;
606}
607
608static enum drm_mode_status
609dw_hdmi_mode_valid(struct drm_connector *connector,
610 const struct drm_display_mode *mode)
611{
612 struct meson_drm *priv = connector->dev->dev_private;
613 unsigned int vclk_freq;
614 unsigned int venc_freq;
615 unsigned int hdmi_freq;
616 int vic = drm_match_cea_mode(mode);
617 enum drm_mode_status status;
618
619 DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
620
621
622 if (connector->display_info.max_tmds_clock &&
623 mode->clock > connector->display_info.max_tmds_clock)
624 return MODE_BAD;
625
626
627 if (!vic) {
628 status = meson_venc_hdmi_supported_mode(mode);
629 if (status != MODE_OK)
630 return status;
631
632 return meson_vclk_dmt_supported_freq(priv, mode->clock);
633
634 } else if (!meson_venc_hdmi_supported_vic(vic))
635 return MODE_BAD;
636
637 vclk_freq = mode->clock;
638
639
640 if (mode->flags & DRM_MODE_FLAG_DBLCLK)
641 vclk_freq *= 2;
642
643 venc_freq = vclk_freq;
644 hdmi_freq = vclk_freq;
645
646
647 if (meson_venc_hdmi_venc_repeat(vic))
648 venc_freq *= 2;
649
650 vclk_freq = max(venc_freq, hdmi_freq);
651
652 if (mode->flags & DRM_MODE_FLAG_DBLCLK)
653 venc_freq /= 2;
654
655 dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
656 vclk_freq, venc_freq, hdmi_freq);
657
658 return meson_vclk_vic_supported_freq(vclk_freq);
659}
660
661
662
663static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
664{
665 drm_encoder_cleanup(encoder);
666}
667
668static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
669 .destroy = meson_venc_hdmi_encoder_destroy,
670};
671
672static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
673 struct drm_crtc_state *crtc_state,
674 struct drm_connector_state *conn_state)
675{
676 return 0;
677}
678
679static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
680{
681 struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
682 struct meson_drm *priv = dw_hdmi->priv;
683
684 DRM_DEBUG_DRIVER("\n");
685
686 writel_bits_relaxed(0x3, 0,
687 priv->io_base + _REG(VPU_HDMI_SETTING));
688
689 writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
690 writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
691}
692
693static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
694{
695 struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
696 struct meson_drm *priv = dw_hdmi->priv;
697
698 DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
699
700 if (priv->venc.hdmi_use_enci)
701 writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
702 else
703 writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
704}
705
706static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
707 struct drm_display_mode *mode,
708 struct drm_display_mode *adjusted_mode)
709{
710 struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
711 struct meson_drm *priv = dw_hdmi->priv;
712 int vic = drm_match_cea_mode(mode);
713
714 DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
715
716
717 meson_venc_hdmi_mode_set(priv, vic, mode);
718
719
720 dw_hdmi_set_vclk(dw_hdmi, mode);
721
722
723 writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
724}
725
726static const struct drm_encoder_helper_funcs
727 meson_venc_hdmi_encoder_helper_funcs = {
728 .atomic_check = meson_venc_hdmi_encoder_atomic_check,
729 .disable = meson_venc_hdmi_encoder_disable,
730 .enable = meson_venc_hdmi_encoder_enable,
731 .mode_set = meson_venc_hdmi_encoder_mode_set,
732};
733
734
735
736static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
737 unsigned int *result)
738{
739 struct meson_dw_hdmi *dw_hdmi = context;
740
741 *result = dw_hdmi->data->dwc_read(dw_hdmi, reg);
742
743 return 0;
744
745}
746
747static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
748 unsigned int val)
749{
750 struct meson_dw_hdmi *dw_hdmi = context;
751
752 dw_hdmi->data->dwc_write(dw_hdmi, reg, val);
753
754 return 0;
755}
756
757static const struct regmap_config meson_dw_hdmi_regmap_config = {
758 .reg_bits = 32,
759 .val_bits = 8,
760 .reg_read = meson_dw_hdmi_reg_read,
761 .reg_write = meson_dw_hdmi_reg_write,
762 .max_register = 0x10000,
763 .fast_io = true,
764};
765
766static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = {
767 .top_read = dw_hdmi_top_read,
768 .top_write = dw_hdmi_top_write,
769 .dwc_read = dw_hdmi_dwc_read,
770 .dwc_write = dw_hdmi_dwc_write,
771};
772
773static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = {
774 .top_read = dw_hdmi_g12a_top_read,
775 .top_write = dw_hdmi_g12a_top_write,
776 .dwc_read = dw_hdmi_g12a_dwc_read,
777 .dwc_write = dw_hdmi_g12a_dwc_write,
778};
779
780static bool meson_hdmi_connector_is_available(struct device *dev)
781{
782 struct device_node *ep, *remote;
783
784
785 ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
786 if (!ep)
787 return false;
788
789
790 remote = of_graph_get_remote_port(ep);
791 if (remote) {
792 of_node_put(ep);
793 return true;
794 }
795
796 of_node_put(ep);
797 of_node_put(remote);
798
799 return false;
800}
801
802static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
803 void *data)
804{
805 struct platform_device *pdev = to_platform_device(dev);
806 const struct meson_dw_hdmi_data *match;
807 struct meson_dw_hdmi *meson_dw_hdmi;
808 struct drm_device *drm = data;
809 struct meson_drm *priv = drm->dev_private;
810 struct dw_hdmi_plat_data *dw_plat_data;
811 struct drm_encoder *encoder;
812 struct resource *res;
813 int irq;
814 int ret;
815
816 DRM_DEBUG_DRIVER("\n");
817
818 if (!meson_hdmi_connector_is_available(dev)) {
819 dev_info(drm->dev, "HDMI Output connector not available\n");
820 return -ENODEV;
821 }
822
823 match = of_device_get_match_data(&pdev->dev);
824 if (!match) {
825 dev_err(&pdev->dev, "failed to get match data\n");
826 return -ENODEV;
827 }
828
829 meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
830 GFP_KERNEL);
831 if (!meson_dw_hdmi)
832 return -ENOMEM;
833
834 meson_dw_hdmi->priv = priv;
835 meson_dw_hdmi->dev = dev;
836 meson_dw_hdmi->data = match;
837 dw_plat_data = &meson_dw_hdmi->dw_plat_data;
838 encoder = &meson_dw_hdmi->encoder;
839
840 meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi");
841 if (IS_ERR(meson_dw_hdmi->hdmi_supply)) {
842 if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER)
843 return -EPROBE_DEFER;
844 meson_dw_hdmi->hdmi_supply = NULL;
845 } else {
846 ret = regulator_enable(meson_dw_hdmi->hdmi_supply);
847 if (ret)
848 return ret;
849 }
850
851 meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
852 "hdmitx_apb");
853 if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
854 dev_err(dev, "Failed to get hdmitx_apb reset\n");
855 return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
856 }
857
858 meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
859 "hdmitx");
860 if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
861 dev_err(dev, "Failed to get hdmitx reset\n");
862 return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
863 }
864
865 meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
866 "hdmitx_phy");
867 if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
868 dev_err(dev, "Failed to get hdmitx_phy reset\n");
869 return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
870 }
871
872 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
873 meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
874 if (IS_ERR(meson_dw_hdmi->hdmitx))
875 return PTR_ERR(meson_dw_hdmi->hdmitx);
876
877 meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr");
878 if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) {
879 dev_err(dev, "Unable to get HDMI pclk\n");
880 return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
881 }
882 clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
883
884 meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci");
885 if (IS_ERR(meson_dw_hdmi->venci_clk)) {
886 dev_err(dev, "Unable to get venci clk\n");
887 return PTR_ERR(meson_dw_hdmi->venci_clk);
888 }
889 clk_prepare_enable(meson_dw_hdmi->venci_clk);
890
891 dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
892 &meson_dw_hdmi_regmap_config);
893 if (IS_ERR(dw_plat_data->regm))
894 return PTR_ERR(dw_plat_data->regm);
895
896 irq = platform_get_irq(pdev, 0);
897 if (irq < 0) {
898 dev_err(dev, "Failed to get hdmi top irq\n");
899 return irq;
900 }
901
902 ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
903 dw_hdmi_top_thread_irq, IRQF_SHARED,
904 "dw_hdmi_top_irq", meson_dw_hdmi);
905 if (ret) {
906 dev_err(dev, "Failed to request hdmi top irq\n");
907 return ret;
908 }
909
910
911
912 drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
913
914 ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
915 DRM_MODE_ENCODER_TMDS, "meson_hdmi");
916 if (ret) {
917 dev_err(priv->dev, "Failed to init HDMI encoder\n");
918 return ret;
919 }
920
921 encoder->possible_crtcs = BIT(0);
922
923 DRM_DEBUG_DRIVER("encoder initialized\n");
924
925
926 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
927
928
929 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
930
931
932 reset_control_reset(meson_dw_hdmi->hdmitx_apb);
933 reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
934 reset_control_reset(meson_dw_hdmi->hdmitx_phy);
935
936
937 if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
938 writel_bits_relaxed(BIT(15), BIT(15),
939 meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
940 writel_bits_relaxed(BIT(15), BIT(15),
941 meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
942 }
943
944
945 meson_dw_hdmi->data->top_write(meson_dw_hdmi,
946 HDMITX_TOP_SW_RESET, 0);
947
948 msleep(20);
949
950 meson_dw_hdmi->data->top_write(meson_dw_hdmi,
951 HDMITX_TOP_CLK_CNTL, 0xff);
952
953
954 meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
955 HDMITX_TOP_INTR_CORE);
956
957 meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
958 HDMITX_TOP_INTR_CORE);
959
960
961
962 dw_plat_data->mode_valid = dw_hdmi_mode_valid;
963 dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
964 dw_plat_data->phy_name = "meson_dw_hdmi_phy";
965 dw_plat_data->phy_data = meson_dw_hdmi;
966 dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
967 dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
968
969 platform_set_drvdata(pdev, meson_dw_hdmi);
970
971 meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
972 &meson_dw_hdmi->dw_plat_data);
973 if (IS_ERR(meson_dw_hdmi->hdmi))
974 return PTR_ERR(meson_dw_hdmi->hdmi);
975
976 DRM_DEBUG_DRIVER("HDMI controller initialized\n");
977
978 return 0;
979}
980
981static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
982 void *data)
983{
984 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
985
986 dw_hdmi_unbind(meson_dw_hdmi->hdmi);
987}
988
989static const struct component_ops meson_dw_hdmi_ops = {
990 .bind = meson_dw_hdmi_bind,
991 .unbind = meson_dw_hdmi_unbind,
992};
993
994static int meson_dw_hdmi_probe(struct platform_device *pdev)
995{
996 return component_add(&pdev->dev, &meson_dw_hdmi_ops);
997}
998
999static int meson_dw_hdmi_remove(struct platform_device *pdev)
1000{
1001 component_del(&pdev->dev, &meson_dw_hdmi_ops);
1002
1003 return 0;
1004}
1005
1006static const struct of_device_id meson_dw_hdmi_of_table[] = {
1007 { .compatible = "amlogic,meson-gxbb-dw-hdmi",
1008 .data = &meson_dw_hdmi_gx_data },
1009 { .compatible = "amlogic,meson-gxl-dw-hdmi",
1010 .data = &meson_dw_hdmi_gx_data },
1011 { .compatible = "amlogic,meson-gxm-dw-hdmi",
1012 .data = &meson_dw_hdmi_gx_data },
1013 { .compatible = "amlogic,meson-g12a-dw-hdmi",
1014 .data = &meson_dw_hdmi_g12a_data },
1015 { }
1016};
1017MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
1018
1019static struct platform_driver meson_dw_hdmi_platform_driver = {
1020 .probe = meson_dw_hdmi_probe,
1021 .remove = meson_dw_hdmi_remove,
1022 .driver = {
1023 .name = DRIVER_NAME,
1024 .of_match_table = meson_dw_hdmi_of_table,
1025 },
1026};
1027module_platform_driver(meson_dw_hdmi_platform_driver);
1028
1029MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
1030MODULE_DESCRIPTION(DRIVER_DESC);
1031MODULE_LICENSE("GPL");
1032