1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
9 #include <linux/component.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/of_graph.h>
14 #include <linux/regulator/consumer.h>
15 #include <linux/reset.h>
17 #include <drm/bridge/dw_hdmi.h>
18 #include <drm/drm_atomic_helper.h>
19 #include <drm/drm_bridge.h>
20 #include <drm/drm_device.h>
21 #include <drm/drm_edid.h>
22 #include <drm/drm_probe_helper.h>
23 #include <drm/drm_print.h>
25 #include <linux/videodev2.h>
27 #include "meson_drv.h"
28 #include "meson_dw_hdmi.h"
29 #include "meson_registers.h"
31 #define DRIVER_NAME "meson-dw-hdmi"
32 #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
37 * HDMI Output is composed of :
39 * - A Synopsys DesignWare HDMI Controller IP
40 * - A TOP control block controlling the Clocks and PHY
41 * - A custom HDMI PHY in order convert video to TMDS signal
45 * ___________________________________
47 * |___________________________________|
49 * | Synopsys HDMI | HDMI PHY |=> TMDS
50 * | Controller |________________|
51 * |___________________________________|<=> DDC
54 * The HDMI TOP block only supports HPD sensing.
55 * The Synopsys HDMI Controller interrupt is routed
56 * through the TOP Block interrupt.
57 * Communication to the TOP Block and the Synopsys
58 * HDMI Controller is done a pair of addr+read/write
60 * The HDMI PHY is configured by registers in the
63 * Pixel data arrives in 4:4:4 format from the VENC
64 * block and the VPU HDMI mux selects either the ENCI
65 * encoder for the 576i or 480i formats or the ENCP
66 * encoder for all the other formats including
67 * interlaced HD formats.
68 * The VENC uses a DVI encoder on top of the ENCI
69 * or ENCP encoders to generate DVI timings for the
72 * GXBB, GXL and GXM embeds the Synopsys DesignWare
73 * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
74 * audio source interfaces.
76 * We handle the following features :
78 * - HPD Rise & Fall interrupt
79 * - HDMI Controller Interrupt
80 * - HDMI PHY Init for 480i to 1080p60
81 * - VENC & HDMI Clock setup for 480i to 1080p60
82 * - VENC Mode setup for 480i to 1080p60
86 * - PHY, Clock and Mode setup for 2k && 4k modes
87 * - SDDC Scrambling mode for HDMI 2.0a
92 /* TOP Block Communication Channel */
93 #define HDMITX_TOP_ADDR_REG 0x0
94 #define HDMITX_TOP_DATA_REG 0x4
95 #define HDMITX_TOP_CTRL_REG 0x8
96 #define HDMITX_TOP_G12A_OFFSET 0x8000
98 /* Controller Communication Channel */
99 #define HDMITX_DWC_ADDR_REG 0x10
100 #define HDMITX_DWC_DATA_REG 0x14
101 #define HDMITX_DWC_CTRL_REG 0x18
104 #define HHI_MEM_PD_REG0 0x100 /* 0x40 */
105 #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */
106 #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */
107 #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */
108 #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */
109 #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */
110 #define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */
111 #define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */
113 static DEFINE_SPINLOCK(reg_lock);
115 enum meson_venc_source {
116 MESON_VENC_SOURCE_NONE = 0,
117 MESON_VENC_SOURCE_ENCI = 1,
118 MESON_VENC_SOURCE_ENCP = 2,
121 struct meson_dw_hdmi;
123 struct meson_dw_hdmi_data {
124 unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi,
126 void (*top_write)(struct meson_dw_hdmi *dw_hdmi,
127 unsigned int addr, unsigned int data);
128 unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi,
130 void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi,
131 unsigned int addr, unsigned int data);
134 struct meson_dw_hdmi {
135 struct dw_hdmi_plat_data dw_plat_data;
136 struct meson_drm *priv;
138 void __iomem *hdmitx;
139 const struct meson_dw_hdmi_data *data;
140 struct reset_control *hdmitx_apb;
141 struct reset_control *hdmitx_ctrl;
142 struct reset_control *hdmitx_phy;
144 struct dw_hdmi *hdmi;
145 struct drm_bridge *bridge;
148 static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
151 return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
154 /* PHY (via TOP bridge) and Controller dedicated register interface */
156 static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
162 spin_lock_irqsave(®_lock, flags);
164 /* ADDR must be written twice */
165 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
166 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
168 /* Read needs a second DATA read */
169 data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
170 data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
172 spin_unlock_irqrestore(®_lock, flags);
177 static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi,
180 return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
183 static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
184 unsigned int addr, unsigned int data)
188 spin_lock_irqsave(®_lock, flags);
190 /* ADDR must be written twice */
191 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
192 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
194 /* Write needs single DATA write */
195 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
197 spin_unlock_irqrestore(®_lock, flags);
200 static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi,
201 unsigned int addr, unsigned int data)
203 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
206 /* Helper to change specific bits in PHY registers */
207 static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
212 unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr);
217 dw_hdmi->data->top_write(dw_hdmi, addr, data);
220 static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
226 spin_lock_irqsave(®_lock, flags);
228 /* ADDR must be written twice */
229 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
230 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
232 /* Read needs a second DATA read */
233 data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
234 data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
236 spin_unlock_irqrestore(®_lock, flags);
241 static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi,
244 return readb(dw_hdmi->hdmitx + addr);
247 static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
248 unsigned int addr, unsigned int data)
252 spin_lock_irqsave(®_lock, flags);
254 /* ADDR must be written twice */
255 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
256 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
258 /* Write needs single DATA write */
259 writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
261 spin_unlock_irqrestore(®_lock, flags);
264 static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi,
265 unsigned int addr, unsigned int data)
267 writeb(data, dw_hdmi->hdmitx + addr);
270 /* Helper to change specific bits in controller registers */
271 static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
276 unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr);
281 dw_hdmi->data->dwc_write(dw_hdmi, addr, data);
286 /* Setup PHY bandwidth modes */
287 static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
288 const struct drm_display_mode *mode,
291 struct meson_drm *priv = dw_hdmi->priv;
292 unsigned int pixel_clock = mode->clock;
294 /* For 420, pixel clock is half unlike venc clock */
295 if (mode_is_420) pixel_clock /= 2;
297 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
298 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
299 if (pixel_clock >= 371250) {
300 /* 5.94Gbps, 3.7125Gbps */
301 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
302 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
303 } else if (pixel_clock >= 297000) {
305 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
306 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
307 } else if (pixel_clock >= 148500) {
309 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
310 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
312 /* 742.5Mbps, and below */
313 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
314 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
316 } else if (dw_hdmi_is_compatible(dw_hdmi,
317 "amlogic,meson-gxbb-dw-hdmi")) {
318 if (pixel_clock >= 371250) {
319 /* 5.94Gbps, 3.7125Gbps */
320 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
321 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
322 } else if (pixel_clock >= 297000) {
324 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
325 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
327 /* 1.485Gbps, and below */
328 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
329 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
331 } else if (dw_hdmi_is_compatible(dw_hdmi,
332 "amlogic,meson-g12a-dw-hdmi")) {
333 if (pixel_clock >= 371250) {
334 /* 5.94Gbps, 3.7125Gbps */
335 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4);
336 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
337 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b);
338 } else if (pixel_clock >= 297000) {
340 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262);
341 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
342 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
344 /* 1.485Gbps, and below */
345 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242);
346 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
347 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
352 static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
354 struct meson_drm *priv = dw_hdmi->priv;
356 /* Enable and software reset */
357 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
361 /* Enable and unreset */
362 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
367 static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
368 const struct drm_display_info *display,
369 const struct drm_display_mode *mode)
371 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
372 bool is_hdmi2_sink = display->hdmi.scdc.supported;
373 struct meson_drm *priv = dw_hdmi->priv;
374 unsigned int wr_clk =
375 readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
376 bool mode_is_420 = false;
378 DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name,
379 mode->clock > 340000 ? 40 : 10);
381 if (drm_mode_is_420_only(display, mode) ||
383 drm_mode_is_420_also(display, mode)))
387 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
389 /* Bring HDMITX MEM output of power down */
390 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
392 /* Bring out of reset */
393 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
395 /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
396 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
399 /* Enable cec_clk and hdcp22_tmdsclk_en */
400 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
403 /* Enable normal output to PHY */
404 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
406 /* TMDS pattern setup */
407 if (mode->clock > 340000 && !mode_is_420) {
408 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
410 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
413 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
415 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
419 /* Load TMDS pattern */
420 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
422 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
424 /* Setup PHY parameters */
425 meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420);
428 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
429 0xffff << 16, 0x0390 << 16);
432 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
433 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
434 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
435 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
438 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
441 /* Disable clock, fifo, fifo_wr */
442 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
444 dw_hdmi_set_high_tmds_clock_ratio(hdmi, display);
448 /* Reset PHY 3 times in a row */
449 meson_dw_hdmi_phy_reset(dw_hdmi);
450 meson_dw_hdmi_phy_reset(dw_hdmi);
451 meson_dw_hdmi_phy_reset(dw_hdmi);
453 /* Temporary Disable VENC video stream */
454 if (priv->venc.hdmi_use_enci)
455 writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
457 writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
459 /* Temporary Disable HDMI video stream to HDMI-TX */
460 writel_bits_relaxed(0x3, 0,
461 priv->io_base + _REG(VPU_HDMI_SETTING));
462 writel_bits_relaxed(0xf << 8, 0,
463 priv->io_base + _REG(VPU_HDMI_SETTING));
465 /* Re-Enable VENC video stream */
466 if (priv->venc.hdmi_use_enci)
467 writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
469 writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
471 /* Push back HDMI clock settings */
472 writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
473 priv->io_base + _REG(VPU_HDMI_SETTING));
475 /* Enable and Select HDMI video source for HDMI-TX */
476 if (priv->venc.hdmi_use_enci)
477 writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
478 priv->io_base + _REG(VPU_HDMI_SETTING));
480 writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
481 priv->io_base + _REG(VPU_HDMI_SETTING));
486 static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
489 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
490 struct meson_drm *priv = dw_hdmi->priv;
492 DRM_DEBUG_DRIVER("\n");
494 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
497 static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
500 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
502 return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
503 connector_status_connected : connector_status_disconnected;
506 static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
509 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
511 /* Setup HPD Filter */
512 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
515 /* Clear interrupts */
516 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
517 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
519 /* Unmask interrupts */
520 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
521 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
522 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
525 static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
526 .init = dw_hdmi_phy_init,
527 .disable = dw_hdmi_phy_disable,
528 .read_hpd = dw_hdmi_read_hpd,
529 .setup_hpd = dw_hdmi_setup_hpd,
532 static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
534 struct meson_dw_hdmi *dw_hdmi = dev_id;
537 stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
538 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
540 /* HPD Events, handle in the threaded interrupt handler */
541 if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
542 dw_hdmi->irq_stat = stat;
543 return IRQ_WAKE_THREAD;
546 /* HDMI Controller Interrupt */
550 /* TOFIX Handle HDCP Interrupts */
555 /* Threaded interrupt handler to manage HPD events */
556 static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
558 struct meson_dw_hdmi *dw_hdmi = dev_id;
559 u32 stat = dw_hdmi->irq_stat;
562 if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
563 bool hpd_connected = false;
565 if (stat & HDMITX_TOP_INTR_HPD_RISE)
566 hpd_connected = true;
568 dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
571 drm_helper_hpd_irq_event(dw_hdmi->bridge->dev);
572 drm_bridge_hpd_notify(dw_hdmi->bridge,
573 hpd_connected ? connector_status_connected
574 : connector_status_disconnected);
582 static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
583 unsigned int *result)
585 struct meson_dw_hdmi *dw_hdmi = context;
587 *result = dw_hdmi->data->dwc_read(dw_hdmi, reg);
593 static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
596 struct meson_dw_hdmi *dw_hdmi = context;
598 dw_hdmi->data->dwc_write(dw_hdmi, reg, val);
603 static const struct regmap_config meson_dw_hdmi_regmap_config = {
606 .reg_read = meson_dw_hdmi_reg_read,
607 .reg_write = meson_dw_hdmi_reg_write,
608 .max_register = 0x10000,
612 static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = {
613 .top_read = dw_hdmi_top_read,
614 .top_write = dw_hdmi_top_write,
615 .dwc_read = dw_hdmi_dwc_read,
616 .dwc_write = dw_hdmi_dwc_write,
619 static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = {
620 .top_read = dw_hdmi_g12a_top_read,
621 .top_write = dw_hdmi_g12a_top_write,
622 .dwc_read = dw_hdmi_g12a_dwc_read,
623 .dwc_write = dw_hdmi_g12a_dwc_write,
626 static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi)
628 struct meson_drm *priv = meson_dw_hdmi->priv;
631 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
633 /* Bring HDMITX MEM output of power down */
634 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
636 /* Reset HDMITX APB & TX & PHY */
637 reset_control_reset(meson_dw_hdmi->hdmitx_apb);
638 reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
639 reset_control_reset(meson_dw_hdmi->hdmitx_phy);
641 /* Enable APB3 fail on error */
642 if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
643 writel_bits_relaxed(BIT(15), BIT(15),
644 meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
645 writel_bits_relaxed(BIT(15), BIT(15),
646 meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
649 /* Bring out of reset */
650 meson_dw_hdmi->data->top_write(meson_dw_hdmi,
651 HDMITX_TOP_SW_RESET, 0);
655 meson_dw_hdmi->data->top_write(meson_dw_hdmi,
656 HDMITX_TOP_CLK_CNTL, 0xff);
658 /* Enable HDMI-TX Interrupt */
659 meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
660 HDMITX_TOP_INTR_CORE);
662 meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
663 HDMITX_TOP_INTR_CORE);
667 static void meson_disable_clk(void *data)
669 clk_disable_unprepare(data);
672 static int meson_enable_clk(struct device *dev, char *name)
677 clk = devm_clk_get(dev, name);
679 dev_err(dev, "Unable to get %s pclk\n", name);
683 ret = clk_prepare_enable(clk);
685 ret = devm_add_action_or_reset(dev, meson_disable_clk, clk);
690 static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
693 struct platform_device *pdev = to_platform_device(dev);
694 const struct meson_dw_hdmi_data *match;
695 struct meson_dw_hdmi *meson_dw_hdmi;
696 struct drm_device *drm = data;
697 struct meson_drm *priv = drm->dev_private;
698 struct dw_hdmi_plat_data *dw_plat_data;
702 DRM_DEBUG_DRIVER("\n");
704 match = of_device_get_match_data(&pdev->dev);
706 dev_err(&pdev->dev, "failed to get match data\n");
710 meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
715 meson_dw_hdmi->priv = priv;
716 meson_dw_hdmi->dev = dev;
717 meson_dw_hdmi->data = match;
718 dw_plat_data = &meson_dw_hdmi->dw_plat_data;
720 ret = devm_regulator_get_enable_optional(dev, "hdmi");
721 if (ret < 0 && ret != -ENODEV)
724 meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
726 if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
727 dev_err(dev, "Failed to get hdmitx_apb reset\n");
728 return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
731 meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
733 if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
734 dev_err(dev, "Failed to get hdmitx reset\n");
735 return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
738 meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
740 if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
741 dev_err(dev, "Failed to get hdmitx_phy reset\n");
742 return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
745 meson_dw_hdmi->hdmitx = devm_platform_ioremap_resource(pdev, 0);
746 if (IS_ERR(meson_dw_hdmi->hdmitx))
747 return PTR_ERR(meson_dw_hdmi->hdmitx);
749 ret = meson_enable_clk(dev, "isfr");
753 ret = meson_enable_clk(dev, "iahb");
757 ret = meson_enable_clk(dev, "venci");
761 dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
762 &meson_dw_hdmi_regmap_config);
763 if (IS_ERR(dw_plat_data->regm))
764 return PTR_ERR(dw_plat_data->regm);
766 irq = platform_get_irq(pdev, 0);
770 ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
771 dw_hdmi_top_thread_irq, IRQF_SHARED,
772 "dw_hdmi_top_irq", meson_dw_hdmi);
774 dev_err(dev, "Failed to request hdmi top irq\n");
778 meson_dw_hdmi_init(meson_dw_hdmi);
780 /* Bridge / Connector */
782 dw_plat_data->priv_data = meson_dw_hdmi;
783 dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
784 dw_plat_data->phy_name = "meson_dw_hdmi_phy";
785 dw_plat_data->phy_data = meson_dw_hdmi;
786 dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
787 dw_plat_data->ycbcr_420_allowed = true;
788 dw_plat_data->disable_cec = true;
789 dw_plat_data->output_port = 1;
791 if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
792 dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
793 dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
794 dw_plat_data->use_drm_infoframe = true;
796 platform_set_drvdata(pdev, meson_dw_hdmi);
798 meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, &meson_dw_hdmi->dw_plat_data);
799 if (IS_ERR(meson_dw_hdmi->hdmi))
800 return PTR_ERR(meson_dw_hdmi->hdmi);
802 meson_dw_hdmi->bridge = of_drm_find_bridge(pdev->dev.of_node);
804 DRM_DEBUG_DRIVER("HDMI controller initialized\n");
809 static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
812 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
814 dw_hdmi_unbind(meson_dw_hdmi->hdmi);
817 static const struct component_ops meson_dw_hdmi_ops = {
818 .bind = meson_dw_hdmi_bind,
819 .unbind = meson_dw_hdmi_unbind,
822 static int __maybe_unused meson_dw_hdmi_pm_suspend(struct device *dev)
824 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
830 meson_dw_hdmi->data->top_write(meson_dw_hdmi,
831 HDMITX_TOP_SW_RESET, 0);
836 static int __maybe_unused meson_dw_hdmi_pm_resume(struct device *dev)
838 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
843 meson_dw_hdmi_init(meson_dw_hdmi);
845 dw_hdmi_resume(meson_dw_hdmi->hdmi);
850 static int meson_dw_hdmi_probe(struct platform_device *pdev)
852 return component_add(&pdev->dev, &meson_dw_hdmi_ops);
855 static int meson_dw_hdmi_remove(struct platform_device *pdev)
857 component_del(&pdev->dev, &meson_dw_hdmi_ops);
862 static const struct dev_pm_ops meson_dw_hdmi_pm_ops = {
863 SET_SYSTEM_SLEEP_PM_OPS(meson_dw_hdmi_pm_suspend,
864 meson_dw_hdmi_pm_resume)
867 static const struct of_device_id meson_dw_hdmi_of_table[] = {
868 { .compatible = "amlogic,meson-gxbb-dw-hdmi",
869 .data = &meson_dw_hdmi_gx_data },
870 { .compatible = "amlogic,meson-gxl-dw-hdmi",
871 .data = &meson_dw_hdmi_gx_data },
872 { .compatible = "amlogic,meson-gxm-dw-hdmi",
873 .data = &meson_dw_hdmi_gx_data },
874 { .compatible = "amlogic,meson-g12a-dw-hdmi",
875 .data = &meson_dw_hdmi_g12a_data },
878 MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
880 static struct platform_driver meson_dw_hdmi_platform_driver = {
881 .probe = meson_dw_hdmi_probe,
882 .remove = meson_dw_hdmi_remove,
885 .of_match_table = meson_dw_hdmi_of_table,
886 .pm = &meson_dw_hdmi_pm_ops,
889 module_platform_driver(meson_dw_hdmi_platform_driver);
891 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
892 MODULE_DESCRIPTION(DRIVER_DESC);
893 MODULE_LICENSE("GPL");