Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 BayLibre, SAS
0004  * Author: Neil Armstrong <narmstrong@baylibre.com>
0005  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/component.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/of_device.h>
0013 #include <linux/of_graph.h>
0014 #include <linux/regulator/consumer.h>
0015 #include <linux/reset.h>
0016 
0017 #include <drm/bridge/dw_hdmi.h>
0018 #include <drm/drm_atomic_helper.h>
0019 #include <drm/drm_bridge.h>
0020 #include <drm/drm_device.h>
0021 #include <drm/drm_edid.h>
0022 #include <drm/drm_probe_helper.h>
0023 #include <drm/drm_print.h>
0024 
0025 #include <linux/videodev2.h>
0026 
0027 #include "meson_drv.h"
0028 #include "meson_dw_hdmi.h"
0029 #include "meson_registers.h"
0030 
0031 #define DRIVER_NAME "meson-dw-hdmi"
0032 #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
0033 
0034 /**
0035  * DOC: HDMI Output
0036  *
0037  * HDMI Output is composed of :
0038  *
0039  * - A Synopsys DesignWare HDMI Controller IP
0040  * - A TOP control block controlling the Clocks and PHY
0041  * - A custom HDMI PHY in order convert video to TMDS signal
0042  *
0043  * .. code::
0044  *
0045  *    ___________________________________
0046  *   |            HDMI TOP               |<= HPD
0047  *   |___________________________________|
0048  *   |                  |                |
0049  *   |  Synopsys HDMI   |   HDMI PHY     |=> TMDS
0050  *   |    Controller    |________________|
0051  *   |___________________________________|<=> DDC
0052  *
0053  *
0054  * The HDMI TOP block only supports HPD sensing.
0055  * The Synopsys HDMI Controller interrupt is routed
0056  * through the TOP Block interrupt.
0057  * Communication to the TOP Block and the Synopsys
0058  * HDMI Controller is done a pair of addr+read/write
0059  * registers.
0060  * The HDMI PHY is configured by registers in the
0061  * HHI register block.
0062  *
0063  * Pixel data arrives in 4:4:4 format from the VENC
0064  * block and the VPU HDMI mux selects either the ENCI
0065  * encoder for the 576i or 480i formats or the ENCP
0066  * encoder for all the other formats including
0067  * interlaced HD formats.
0068  * The VENC uses a DVI encoder on top of the ENCI
0069  * or ENCP encoders to generate DVI timings for the
0070  * HDMI controller.
0071  *
0072  * GXBB, GXL and GXM embeds the Synopsys DesignWare
0073  * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
0074  * audio source interfaces.
0075  *
0076  * We handle the following features :
0077  *
0078  * - HPD Rise & Fall interrupt
0079  * - HDMI Controller Interrupt
0080  * - HDMI PHY Init for 480i to 1080p60
0081  * - VENC & HDMI Clock setup for 480i to 1080p60
0082  * - VENC Mode setup for 480i to 1080p60
0083  *
0084  * What is missing :
0085  *
0086  * - PHY, Clock and Mode setup for 2k && 4k modes
0087  * - SDDC Scrambling mode for HDMI 2.0a
0088  * - HDCP Setup
0089  * - CEC Management
0090  */
0091 
0092 /* TOP Block Communication Channel */
0093 #define HDMITX_TOP_ADDR_REG 0x0
0094 #define HDMITX_TOP_DATA_REG 0x4
0095 #define HDMITX_TOP_CTRL_REG 0x8
0096 #define HDMITX_TOP_G12A_OFFSET  0x8000
0097 
0098 /* Controller Communication Channel */
0099 #define HDMITX_DWC_ADDR_REG 0x10
0100 #define HDMITX_DWC_DATA_REG 0x14
0101 #define HDMITX_DWC_CTRL_REG 0x18
0102 
0103 /* HHI Registers */
0104 #define HHI_MEM_PD_REG0     0x100 /* 0x40 */
0105 #define HHI_HDMI_CLK_CNTL   0x1cc /* 0x73 */
0106 #define HHI_HDMI_PHY_CNTL0  0x3a0 /* 0xe8 */
0107 #define HHI_HDMI_PHY_CNTL1  0x3a4 /* 0xe9 */
0108 #define HHI_HDMI_PHY_CNTL2  0x3a8 /* 0xea */
0109 #define HHI_HDMI_PHY_CNTL3  0x3ac /* 0xeb */
0110 #define HHI_HDMI_PHY_CNTL4  0x3b0 /* 0xec */
0111 #define HHI_HDMI_PHY_CNTL5  0x3b4 /* 0xed */
0112 
0113 static DEFINE_SPINLOCK(reg_lock);
0114 
0115 enum meson_venc_source {
0116     MESON_VENC_SOURCE_NONE = 0,
0117     MESON_VENC_SOURCE_ENCI = 1,
0118     MESON_VENC_SOURCE_ENCP = 2,
0119 };
0120 
0121 struct meson_dw_hdmi;
0122 
0123 struct meson_dw_hdmi_data {
0124     unsigned int    (*top_read)(struct meson_dw_hdmi *dw_hdmi,
0125                     unsigned int addr);
0126     void        (*top_write)(struct meson_dw_hdmi *dw_hdmi,
0127                      unsigned int addr, unsigned int data);
0128     unsigned int    (*dwc_read)(struct meson_dw_hdmi *dw_hdmi,
0129                     unsigned int addr);
0130     void        (*dwc_write)(struct meson_dw_hdmi *dw_hdmi,
0131                      unsigned int addr, unsigned int data);
0132 };
0133 
0134 struct meson_dw_hdmi {
0135     struct dw_hdmi_plat_data dw_plat_data;
0136     struct meson_drm *priv;
0137     struct device *dev;
0138     void __iomem *hdmitx;
0139     const struct meson_dw_hdmi_data *data;
0140     struct reset_control *hdmitx_apb;
0141     struct reset_control *hdmitx_ctrl;
0142     struct reset_control *hdmitx_phy;
0143     struct regulator *hdmi_supply;
0144     u32 irq_stat;
0145     struct dw_hdmi *hdmi;
0146     struct drm_bridge *bridge;
0147 };
0148 
0149 static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
0150                     const char *compat)
0151 {
0152     return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
0153 }
0154 
0155 /* PHY (via TOP bridge) and Controller dedicated register interface */
0156 
0157 static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
0158                      unsigned int addr)
0159 {
0160     unsigned long flags;
0161     unsigned int data;
0162 
0163     spin_lock_irqsave(&reg_lock, flags);
0164 
0165     /* ADDR must be written twice */
0166     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0167     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0168 
0169     /* Read needs a second DATA read */
0170     data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
0171     data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
0172 
0173     spin_unlock_irqrestore(&reg_lock, flags);
0174 
0175     return data;
0176 }
0177 
0178 static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi,
0179                       unsigned int addr)
0180 {
0181     return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
0182 }
0183 
0184 static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
0185                      unsigned int addr, unsigned int data)
0186 {
0187     unsigned long flags;
0188 
0189     spin_lock_irqsave(&reg_lock, flags);
0190 
0191     /* ADDR must be written twice */
0192     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0193     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0194 
0195     /* Write needs single DATA write */
0196     writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
0197 
0198     spin_unlock_irqrestore(&reg_lock, flags);
0199 }
0200 
0201 static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi,
0202                       unsigned int addr, unsigned int data)
0203 {
0204     writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
0205 }
0206 
0207 /* Helper to change specific bits in PHY registers */
0208 static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
0209                       unsigned int addr,
0210                       unsigned int mask,
0211                       unsigned int val)
0212 {
0213     unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr);
0214 
0215     data &= ~mask;
0216     data |= val;
0217 
0218     dw_hdmi->data->top_write(dw_hdmi, addr, data);
0219 }
0220 
0221 static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
0222                      unsigned int addr)
0223 {
0224     unsigned long flags;
0225     unsigned int data;
0226 
0227     spin_lock_irqsave(&reg_lock, flags);
0228 
0229     /* ADDR must be written twice */
0230     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0231     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0232 
0233     /* Read needs a second DATA read */
0234     data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
0235     data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
0236 
0237     spin_unlock_irqrestore(&reg_lock, flags);
0238 
0239     return data;
0240 }
0241 
0242 static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi,
0243                       unsigned int addr)
0244 {
0245     return readb(dw_hdmi->hdmitx + addr);
0246 }
0247 
0248 static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
0249                      unsigned int addr, unsigned int data)
0250 {
0251     unsigned long flags;
0252 
0253     spin_lock_irqsave(&reg_lock, flags);
0254 
0255     /* ADDR must be written twice */
0256     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0257     writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0258 
0259     /* Write needs single DATA write */
0260     writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
0261 
0262     spin_unlock_irqrestore(&reg_lock, flags);
0263 }
0264 
0265 static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi,
0266                       unsigned int addr, unsigned int data)
0267 {
0268     writeb(data, dw_hdmi->hdmitx + addr);
0269 }
0270 
0271 /* Helper to change specific bits in controller registers */
0272 static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
0273                       unsigned int addr,
0274                       unsigned int mask,
0275                       unsigned int val)
0276 {
0277     unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr);
0278 
0279     data &= ~mask;
0280     data |= val;
0281 
0282     dw_hdmi->data->dwc_write(dw_hdmi, addr, data);
0283 }
0284 
0285 /* Bridge */
0286 
0287 /* Setup PHY bandwidth modes */
0288 static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
0289                       const struct drm_display_mode *mode,
0290                       bool mode_is_420)
0291 {
0292     struct meson_drm *priv = dw_hdmi->priv;
0293     unsigned int pixel_clock = mode->clock;
0294 
0295     /* For 420, pixel clock is half unlike venc clock */
0296     if (mode_is_420) pixel_clock /= 2;
0297 
0298     if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
0299         dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
0300         if (pixel_clock >= 371250) {
0301             /* 5.94Gbps, 3.7125Gbps */
0302             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
0303             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
0304         } else if (pixel_clock >= 297000) {
0305             /* 2.97Gbps */
0306             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
0307             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
0308         } else if (pixel_clock >= 148500) {
0309             /* 1.485Gbps */
0310             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
0311             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
0312         } else {
0313             /* 742.5Mbps, and below */
0314             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
0315             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
0316         }
0317     } else if (dw_hdmi_is_compatible(dw_hdmi,
0318                      "amlogic,meson-gxbb-dw-hdmi")) {
0319         if (pixel_clock >= 371250) {
0320             /* 5.94Gbps, 3.7125Gbps */
0321             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
0322             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
0323         } else if (pixel_clock >= 297000) {
0324             /* 2.97Gbps */
0325             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
0326             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
0327         } else {
0328             /* 1.485Gbps, and below */
0329             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
0330             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
0331         }
0332     } else if (dw_hdmi_is_compatible(dw_hdmi,
0333                      "amlogic,meson-g12a-dw-hdmi")) {
0334         if (pixel_clock >= 371250) {
0335             /* 5.94Gbps, 3.7125Gbps */
0336             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4);
0337             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
0338             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b);
0339         } else if (pixel_clock >= 297000) {
0340             /* 2.97Gbps */
0341             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262);
0342             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
0343             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
0344         } else {
0345             /* 1.485Gbps, and below */
0346             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242);
0347             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
0348             regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
0349         }
0350     }
0351 }
0352 
0353 static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
0354 {
0355     struct meson_drm *priv = dw_hdmi->priv;
0356 
0357     /* Enable and software reset */
0358     regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
0359 
0360     mdelay(2);
0361 
0362     /* Enable and unreset */
0363     regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
0364 
0365     mdelay(2);
0366 }
0367 
0368 static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
0369                 const struct drm_display_info *display,
0370                 const struct drm_display_mode *mode)
0371 {
0372     struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
0373     bool is_hdmi2_sink = display->hdmi.scdc.supported;
0374     struct meson_drm *priv = dw_hdmi->priv;
0375     unsigned int wr_clk =
0376         readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
0377     bool mode_is_420 = false;
0378 
0379     DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name,
0380              mode->clock > 340000 ? 40 : 10);
0381 
0382     if (drm_mode_is_420_only(display, mode) ||
0383         (!is_hdmi2_sink &&
0384          drm_mode_is_420_also(display, mode)))
0385         mode_is_420 = true;
0386 
0387     /* Enable clocks */
0388     regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
0389 
0390     /* Bring HDMITX MEM output of power down */
0391     regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
0392 
0393     /* Bring out of reset */
0394     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET,  0);
0395 
0396     /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
0397     dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
0398                    0x3, 0x3);
0399 
0400     /* Enable cec_clk and hdcp22_tmdsclk_en */
0401     dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
0402                    0x3 << 4, 0x3 << 4);
0403 
0404     /* Enable normal output to PHY */
0405     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
0406 
0407     /* TMDS pattern setup */
0408     if (mode->clock > 340000 && !mode_is_420) {
0409         dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
0410                   0);
0411         dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
0412                   0x03ff03ff);
0413     } else {
0414         dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
0415                   0x001f001f);
0416         dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
0417                   0x001f001f);
0418     }
0419 
0420     /* Load TMDS pattern */
0421     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
0422     msleep(20);
0423     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
0424 
0425     /* Setup PHY parameters */
0426     meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420);
0427 
0428     /* Setup PHY */
0429     regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
0430                0xffff << 16, 0x0390 << 16);
0431 
0432     /* BIT_INVERT */
0433     if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
0434         dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
0435         dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
0436         regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
0437                    BIT(17), 0);
0438     else
0439         regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
0440                    BIT(17), BIT(17));
0441 
0442     /* Disable clock, fifo, fifo_wr */
0443     regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
0444 
0445     dw_hdmi_set_high_tmds_clock_ratio(hdmi, display);
0446 
0447     msleep(100);
0448 
0449     /* Reset PHY 3 times in a row */
0450     meson_dw_hdmi_phy_reset(dw_hdmi);
0451     meson_dw_hdmi_phy_reset(dw_hdmi);
0452     meson_dw_hdmi_phy_reset(dw_hdmi);
0453 
0454     /* Temporary Disable VENC video stream */
0455     if (priv->venc.hdmi_use_enci)
0456         writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
0457     else
0458         writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
0459 
0460     /* Temporary Disable HDMI video stream to HDMI-TX */
0461     writel_bits_relaxed(0x3, 0,
0462                 priv->io_base + _REG(VPU_HDMI_SETTING));
0463     writel_bits_relaxed(0xf << 8, 0,
0464                 priv->io_base + _REG(VPU_HDMI_SETTING));
0465 
0466     /* Re-Enable VENC video stream */
0467     if (priv->venc.hdmi_use_enci)
0468         writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
0469     else
0470         writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
0471 
0472     /* Push back HDMI clock settings */
0473     writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
0474                 priv->io_base + _REG(VPU_HDMI_SETTING));
0475 
0476     /* Enable and Select HDMI video source for HDMI-TX */
0477     if (priv->venc.hdmi_use_enci)
0478         writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
0479                     priv->io_base + _REG(VPU_HDMI_SETTING));
0480     else
0481         writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
0482                     priv->io_base + _REG(VPU_HDMI_SETTING));
0483 
0484     return 0;
0485 }
0486 
0487 static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
0488                 void *data)
0489 {
0490     struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
0491     struct meson_drm *priv = dw_hdmi->priv;
0492 
0493     DRM_DEBUG_DRIVER("\n");
0494 
0495     regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
0496 }
0497 
0498 static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
0499                  void *data)
0500 {
0501     struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
0502 
0503     return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
0504         connector_status_connected : connector_status_disconnected;
0505 }
0506 
0507 static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
0508                   void *data)
0509 {
0510     struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
0511 
0512     /* Setup HPD Filter */
0513     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
0514               (0xa << 12) | 0xa0);
0515 
0516     /* Clear interrupts */
0517     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
0518               HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
0519 
0520     /* Unmask interrupts */
0521     dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
0522             HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
0523             HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
0524 }
0525 
0526 static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
0527     .init = dw_hdmi_phy_init,
0528     .disable = dw_hdmi_phy_disable,
0529     .read_hpd = dw_hdmi_read_hpd,
0530     .setup_hpd = dw_hdmi_setup_hpd,
0531 };
0532 
0533 static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
0534 {
0535     struct meson_dw_hdmi *dw_hdmi = dev_id;
0536     u32 stat;
0537 
0538     stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
0539     dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
0540 
0541     /* HPD Events, handle in the threaded interrupt handler */
0542     if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
0543         dw_hdmi->irq_stat = stat;
0544         return IRQ_WAKE_THREAD;
0545     }
0546 
0547     /* HDMI Controller Interrupt */
0548     if (stat & 1)
0549         return IRQ_NONE;
0550 
0551     /* TOFIX Handle HDCP Interrupts */
0552 
0553     return IRQ_HANDLED;
0554 }
0555 
0556 /* Threaded interrupt handler to manage HPD events */
0557 static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
0558 {
0559     struct meson_dw_hdmi *dw_hdmi = dev_id;
0560     u32 stat = dw_hdmi->irq_stat;
0561 
0562     /* HPD Events */
0563     if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
0564         bool hpd_connected = false;
0565 
0566         if (stat & HDMITX_TOP_INTR_HPD_RISE)
0567             hpd_connected = true;
0568 
0569         dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
0570                        hpd_connected);
0571 
0572         drm_helper_hpd_irq_event(dw_hdmi->bridge->dev);
0573         drm_bridge_hpd_notify(dw_hdmi->bridge,
0574                       hpd_connected ? connector_status_connected
0575                             : connector_status_disconnected);
0576     }
0577 
0578     return IRQ_HANDLED;
0579 }
0580 
0581 /* DW HDMI Regmap */
0582 
0583 static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
0584                   unsigned int *result)
0585 {
0586     struct meson_dw_hdmi *dw_hdmi = context;
0587 
0588     *result = dw_hdmi->data->dwc_read(dw_hdmi, reg);
0589 
0590     return 0;
0591 
0592 }
0593 
0594 static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
0595                    unsigned int val)
0596 {
0597     struct meson_dw_hdmi *dw_hdmi = context;
0598 
0599     dw_hdmi->data->dwc_write(dw_hdmi, reg, val);
0600 
0601     return 0;
0602 }
0603 
0604 static const struct regmap_config meson_dw_hdmi_regmap_config = {
0605     .reg_bits = 32,
0606     .val_bits = 8,
0607     .reg_read = meson_dw_hdmi_reg_read,
0608     .reg_write = meson_dw_hdmi_reg_write,
0609     .max_register = 0x10000,
0610     .fast_io = true,
0611 };
0612 
0613 static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = {
0614     .top_read = dw_hdmi_top_read,
0615     .top_write = dw_hdmi_top_write,
0616     .dwc_read = dw_hdmi_dwc_read,
0617     .dwc_write = dw_hdmi_dwc_write,
0618 };
0619 
0620 static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = {
0621     .top_read = dw_hdmi_g12a_top_read,
0622     .top_write = dw_hdmi_g12a_top_write,
0623     .dwc_read = dw_hdmi_g12a_dwc_read,
0624     .dwc_write = dw_hdmi_g12a_dwc_write,
0625 };
0626 
0627 static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi)
0628 {
0629     struct meson_drm *priv = meson_dw_hdmi->priv;
0630 
0631     /* Enable clocks */
0632     regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
0633 
0634     /* Bring HDMITX MEM output of power down */
0635     regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
0636 
0637     /* Reset HDMITX APB & TX & PHY */
0638     reset_control_reset(meson_dw_hdmi->hdmitx_apb);
0639     reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
0640     reset_control_reset(meson_dw_hdmi->hdmitx_phy);
0641 
0642     /* Enable APB3 fail on error */
0643     if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
0644         writel_bits_relaxed(BIT(15), BIT(15),
0645                     meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
0646         writel_bits_relaxed(BIT(15), BIT(15),
0647                     meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
0648     }
0649 
0650     /* Bring out of reset */
0651     meson_dw_hdmi->data->top_write(meson_dw_hdmi,
0652                        HDMITX_TOP_SW_RESET,  0);
0653 
0654     msleep(20);
0655 
0656     meson_dw_hdmi->data->top_write(meson_dw_hdmi,
0657                        HDMITX_TOP_CLK_CNTL, 0xff);
0658 
0659     /* Enable HDMI-TX Interrupt */
0660     meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
0661                        HDMITX_TOP_INTR_CORE);
0662 
0663     meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
0664                        HDMITX_TOP_INTR_CORE);
0665 
0666 }
0667 
0668 static void meson_disable_regulator(void *data)
0669 {
0670     regulator_disable(data);
0671 }
0672 
0673 static void meson_disable_clk(void *data)
0674 {
0675     clk_disable_unprepare(data);
0676 }
0677 
0678 static int meson_enable_clk(struct device *dev, char *name)
0679 {
0680     struct clk *clk;
0681     int ret;
0682 
0683     clk = devm_clk_get(dev, name);
0684     if (IS_ERR(clk)) {
0685         dev_err(dev, "Unable to get %s pclk\n", name);
0686         return PTR_ERR(clk);
0687     }
0688 
0689     ret = clk_prepare_enable(clk);
0690     if (!ret)
0691         ret = devm_add_action_or_reset(dev, meson_disable_clk, clk);
0692 
0693     return ret;
0694 }
0695 
0696 static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
0697                 void *data)
0698 {
0699     struct platform_device *pdev = to_platform_device(dev);
0700     const struct meson_dw_hdmi_data *match;
0701     struct meson_dw_hdmi *meson_dw_hdmi;
0702     struct drm_device *drm = data;
0703     struct meson_drm *priv = drm->dev_private;
0704     struct dw_hdmi_plat_data *dw_plat_data;
0705     int irq;
0706     int ret;
0707 
0708     DRM_DEBUG_DRIVER("\n");
0709 
0710     match = of_device_get_match_data(&pdev->dev);
0711     if (!match) {
0712         dev_err(&pdev->dev, "failed to get match data\n");
0713         return -ENODEV;
0714     }
0715 
0716     meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
0717                      GFP_KERNEL);
0718     if (!meson_dw_hdmi)
0719         return -ENOMEM;
0720 
0721     meson_dw_hdmi->priv = priv;
0722     meson_dw_hdmi->dev = dev;
0723     meson_dw_hdmi->data = match;
0724     dw_plat_data = &meson_dw_hdmi->dw_plat_data;
0725 
0726     meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi");
0727     if (IS_ERR(meson_dw_hdmi->hdmi_supply)) {
0728         if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER)
0729             return -EPROBE_DEFER;
0730         meson_dw_hdmi->hdmi_supply = NULL;
0731     } else {
0732         ret = regulator_enable(meson_dw_hdmi->hdmi_supply);
0733         if (ret)
0734             return ret;
0735         ret = devm_add_action_or_reset(dev, meson_disable_regulator,
0736                            meson_dw_hdmi->hdmi_supply);
0737         if (ret)
0738             return ret;
0739     }
0740 
0741     meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
0742                         "hdmitx_apb");
0743     if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
0744         dev_err(dev, "Failed to get hdmitx_apb reset\n");
0745         return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
0746     }
0747 
0748     meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
0749                         "hdmitx");
0750     if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
0751         dev_err(dev, "Failed to get hdmitx reset\n");
0752         return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
0753     }
0754 
0755     meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
0756                         "hdmitx_phy");
0757     if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
0758         dev_err(dev, "Failed to get hdmitx_phy reset\n");
0759         return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
0760     }
0761 
0762     meson_dw_hdmi->hdmitx = devm_platform_ioremap_resource(pdev, 0);
0763     if (IS_ERR(meson_dw_hdmi->hdmitx))
0764         return PTR_ERR(meson_dw_hdmi->hdmitx);
0765 
0766     ret = meson_enable_clk(dev, "isfr");
0767     if (ret)
0768         return ret;
0769 
0770     ret = meson_enable_clk(dev, "iahb");
0771     if (ret)
0772         return ret;
0773 
0774     ret = meson_enable_clk(dev, "venci");
0775     if (ret)
0776         return ret;
0777 
0778     dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
0779                           &meson_dw_hdmi_regmap_config);
0780     if (IS_ERR(dw_plat_data->regm))
0781         return PTR_ERR(dw_plat_data->regm);
0782 
0783     irq = platform_get_irq(pdev, 0);
0784     if (irq < 0)
0785         return irq;
0786 
0787     ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
0788                     dw_hdmi_top_thread_irq, IRQF_SHARED,
0789                     "dw_hdmi_top_irq", meson_dw_hdmi);
0790     if (ret) {
0791         dev_err(dev, "Failed to request hdmi top irq\n");
0792         return ret;
0793     }
0794 
0795     meson_dw_hdmi_init(meson_dw_hdmi);
0796 
0797     /* Bridge / Connector */
0798 
0799     dw_plat_data->priv_data = meson_dw_hdmi;
0800     dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
0801     dw_plat_data->phy_name = "meson_dw_hdmi_phy";
0802     dw_plat_data->phy_data = meson_dw_hdmi;
0803     dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
0804     dw_plat_data->ycbcr_420_allowed = true;
0805     dw_plat_data->disable_cec = true;
0806     dw_plat_data->output_port = 1;
0807 
0808     if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
0809         dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
0810         dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
0811         dw_plat_data->use_drm_infoframe = true;
0812 
0813     platform_set_drvdata(pdev, meson_dw_hdmi);
0814 
0815     meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, &meson_dw_hdmi->dw_plat_data);
0816     if (IS_ERR(meson_dw_hdmi->hdmi))
0817         return PTR_ERR(meson_dw_hdmi->hdmi);
0818 
0819     meson_dw_hdmi->bridge = of_drm_find_bridge(pdev->dev.of_node);
0820 
0821     DRM_DEBUG_DRIVER("HDMI controller initialized\n");
0822 
0823     return 0;
0824 }
0825 
0826 static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
0827                    void *data)
0828 {
0829     struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
0830 
0831     dw_hdmi_unbind(meson_dw_hdmi->hdmi);
0832 }
0833 
0834 static const struct component_ops meson_dw_hdmi_ops = {
0835     .bind   = meson_dw_hdmi_bind,
0836     .unbind = meson_dw_hdmi_unbind,
0837 };
0838 
0839 static int __maybe_unused meson_dw_hdmi_pm_suspend(struct device *dev)
0840 {
0841     struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
0842 
0843     if (!meson_dw_hdmi)
0844         return 0;
0845 
0846     /* Reset TOP */
0847     meson_dw_hdmi->data->top_write(meson_dw_hdmi,
0848                        HDMITX_TOP_SW_RESET, 0);
0849 
0850     return 0;
0851 }
0852 
0853 static int __maybe_unused meson_dw_hdmi_pm_resume(struct device *dev)
0854 {
0855     struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
0856 
0857     if (!meson_dw_hdmi)
0858         return 0;
0859 
0860     meson_dw_hdmi_init(meson_dw_hdmi);
0861 
0862     dw_hdmi_resume(meson_dw_hdmi->hdmi);
0863 
0864     return 0;
0865 }
0866 
0867 static int meson_dw_hdmi_probe(struct platform_device *pdev)
0868 {
0869     return component_add(&pdev->dev, &meson_dw_hdmi_ops);
0870 }
0871 
0872 static int meson_dw_hdmi_remove(struct platform_device *pdev)
0873 {
0874     component_del(&pdev->dev, &meson_dw_hdmi_ops);
0875 
0876     return 0;
0877 }
0878 
0879 static const struct dev_pm_ops meson_dw_hdmi_pm_ops = {
0880     SET_SYSTEM_SLEEP_PM_OPS(meson_dw_hdmi_pm_suspend,
0881                 meson_dw_hdmi_pm_resume)
0882 };
0883 
0884 static const struct of_device_id meson_dw_hdmi_of_table[] = {
0885     { .compatible = "amlogic,meson-gxbb-dw-hdmi",
0886       .data = &meson_dw_hdmi_gx_data },
0887     { .compatible = "amlogic,meson-gxl-dw-hdmi",
0888       .data = &meson_dw_hdmi_gx_data },
0889     { .compatible = "amlogic,meson-gxm-dw-hdmi",
0890       .data = &meson_dw_hdmi_gx_data },
0891     { .compatible = "amlogic,meson-g12a-dw-hdmi",
0892       .data = &meson_dw_hdmi_g12a_data },
0893     { }
0894 };
0895 MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
0896 
0897 static struct platform_driver meson_dw_hdmi_platform_driver = {
0898     .probe      = meson_dw_hdmi_probe,
0899     .remove     = meson_dw_hdmi_remove,
0900     .driver     = {
0901         .name       = DRIVER_NAME,
0902         .of_match_table = meson_dw_hdmi_of_table,
0903         .pm = &meson_dw_hdmi_pm_ops,
0904     },
0905 };
0906 module_platform_driver(meson_dw_hdmi_platform_driver);
0907 
0908 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0909 MODULE_DESCRIPTION(DRIVER_DESC);
0910 MODULE_LICENSE("GPL");