0001
0002
0003
0004
0005
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
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
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
0099 #define HDMITX_DWC_ADDR_REG 0x10
0100 #define HDMITX_DWC_DATA_REG 0x14
0101 #define HDMITX_DWC_CTRL_REG 0x18
0102
0103
0104 #define HHI_MEM_PD_REG0 0x100
0105 #define HHI_HDMI_CLK_CNTL 0x1cc
0106 #define HHI_HDMI_PHY_CNTL0 0x3a0
0107 #define HHI_HDMI_PHY_CNTL1 0x3a4
0108 #define HHI_HDMI_PHY_CNTL2 0x3a8
0109 #define HHI_HDMI_PHY_CNTL3 0x3ac
0110 #define HHI_HDMI_PHY_CNTL4 0x3b0
0111 #define HHI_HDMI_PHY_CNTL5 0x3b4
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
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(®_lock, flags);
0164
0165
0166 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0167 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0168
0169
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(®_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(®_lock, flags);
0190
0191
0192 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0193 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
0194
0195
0196 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
0197
0198 spin_unlock_irqrestore(®_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
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(®_lock, flags);
0228
0229
0230 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0231 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0232
0233
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(®_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(®_lock, flags);
0254
0255
0256 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0257 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
0258
0259
0260 writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
0261
0262 spin_unlock_irqrestore(®_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
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
0286
0287
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
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
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
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
0310 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
0311 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
0312 } else {
0313
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
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
0325 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
0326 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
0327 } else {
0328
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
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
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
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
0358 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
0359
0360 mdelay(2);
0361
0362
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
0388 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
0389
0390
0391 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
0392
0393
0394 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
0395
0396
0397 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
0398 0x3, 0x3);
0399
0400
0401 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
0402 0x3 << 4, 0x3 << 4);
0403
0404
0405 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
0406
0407
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
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
0426 meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420);
0427
0428
0429 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
0430 0xffff << 16, 0x0390 << 16);
0431
0432
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
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
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
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
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
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
0473 writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
0474 priv->io_base + _REG(VPU_HDMI_SETTING));
0475
0476
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
0513 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
0514 (0xa << 12) | 0xa0);
0515
0516
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
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
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
0548 if (stat & 1)
0549 return IRQ_NONE;
0550
0551
0552
0553 return IRQ_HANDLED;
0554 }
0555
0556
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
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
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
0632 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
0633
0634
0635 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
0636
0637
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
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
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
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
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
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");