meson_dw_hdmi.c (25890B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2016 BayLibre, SAS 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 6 */ 7 8#include <linux/clk.h> 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> 16 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> 24 25#include <linux/videodev2.h> 26 27#include "meson_drv.h" 28#include "meson_dw_hdmi.h" 29#include "meson_registers.h" 30 31#define DRIVER_NAME "meson-dw-hdmi" 32#define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" 33 34/** 35 * DOC: HDMI Output 36 * 37 * HDMI Output is composed of : 38 * 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 42 * 43 * .. code:: 44 * 45 * ___________________________________ 46 * | HDMI TOP |<= HPD 47 * |___________________________________| 48 * | | | 49 * | Synopsys HDMI | HDMI PHY |=> TMDS 50 * | Controller |________________| 51 * |___________________________________|<=> DDC 52 * 53 * 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 59 * registers. 60 * The HDMI PHY is configured by registers in the 61 * HHI register block. 62 * 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 70 * HDMI controller. 71 * 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. 75 * 76 * We handle the following features : 77 * 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 83 * 84 * What is missing : 85 * 86 * - PHY, Clock and Mode setup for 2k && 4k modes 87 * - SDDC Scrambling mode for HDMI 2.0a 88 * - HDCP Setup 89 * - CEC Management 90 */ 91 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 97 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 102 103/* HHI Registers */ 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 */ 112 113static DEFINE_SPINLOCK(reg_lock); 114 115enum meson_venc_source { 116 MESON_VENC_SOURCE_NONE = 0, 117 MESON_VENC_SOURCE_ENCI = 1, 118 MESON_VENC_SOURCE_ENCP = 2, 119}; 120 121struct meson_dw_hdmi; 122 123struct meson_dw_hdmi_data { 124 unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi, 125 unsigned int addr); 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, 129 unsigned int addr); 130 void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, 131 unsigned int addr, unsigned int data); 132}; 133 134struct meson_dw_hdmi { 135 struct dw_hdmi_plat_data dw_plat_data; 136 struct meson_drm *priv; 137 struct device *dev; 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; 143 struct regulator *hdmi_supply; 144 u32 irq_stat; 145 struct dw_hdmi *hdmi; 146 struct drm_bridge *bridge; 147}; 148 149static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi, 150 const char *compat) 151{ 152 return of_device_is_compatible(dw_hdmi->dev->of_node, compat); 153} 154 155/* PHY (via TOP bridge) and Controller dedicated register interface */ 156 157static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, 158 unsigned int addr) 159{ 160 unsigned long flags; 161 unsigned int data; 162 163 spin_lock_irqsave(®_lock, flags); 164 165 /* ADDR must be written twice */ 166 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 167 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 168 169 /* Read needs a second DATA read */ 170 data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); 171 data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); 172 173 spin_unlock_irqrestore(®_lock, flags); 174 175 return data; 176} 177 178static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi, 179 unsigned int addr) 180{ 181 return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); 182} 183 184static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, 185 unsigned int addr, unsigned int data) 186{ 187 unsigned long flags; 188 189 spin_lock_irqsave(®_lock, flags); 190 191 /* ADDR must be written twice */ 192 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 193 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 194 195 /* Write needs single DATA write */ 196 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); 197 198 spin_unlock_irqrestore(®_lock, flags); 199} 200 201static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi, 202 unsigned int addr, unsigned int data) 203{ 204 writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); 205} 206 207/* Helper to change specific bits in PHY registers */ 208static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, 209 unsigned int addr, 210 unsigned int mask, 211 unsigned int val) 212{ 213 unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr); 214 215 data &= ~mask; 216 data |= val; 217 218 dw_hdmi->data->top_write(dw_hdmi, addr, data); 219} 220 221static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, 222 unsigned int addr) 223{ 224 unsigned long flags; 225 unsigned int data; 226 227 spin_lock_irqsave(®_lock, flags); 228 229 /* ADDR must be written twice */ 230 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 231 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 232 233 /* Read needs a second DATA read */ 234 data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); 235 data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); 236 237 spin_unlock_irqrestore(®_lock, flags); 238 239 return data; 240} 241 242static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi, 243 unsigned int addr) 244{ 245 return readb(dw_hdmi->hdmitx + addr); 246} 247 248static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, 249 unsigned int addr, unsigned int data) 250{ 251 unsigned long flags; 252 253 spin_lock_irqsave(®_lock, flags); 254 255 /* ADDR must be written twice */ 256 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 257 writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 258 259 /* Write needs single DATA write */ 260 writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); 261 262 spin_unlock_irqrestore(®_lock, flags); 263} 264 265static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi, 266 unsigned int addr, unsigned int data) 267{ 268 writeb(data, dw_hdmi->hdmitx + addr); 269} 270 271/* Helper to change specific bits in controller registers */ 272static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, 273 unsigned int addr, 274 unsigned int mask, 275 unsigned int val) 276{ 277 unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr); 278 279 data &= ~mask; 280 data |= val; 281 282 dw_hdmi->data->dwc_write(dw_hdmi, addr, data); 283} 284 285/* Bridge */ 286 287/* Setup PHY bandwidth modes */ 288static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, 289 const struct drm_display_mode *mode, 290 bool mode_is_420) 291{ 292 struct meson_drm *priv = dw_hdmi->priv; 293 unsigned int pixel_clock = mode->clock; 294 295 /* For 420, pixel clock is half unlike venc clock */ 296 if (mode_is_420) pixel_clock /= 2; 297 298 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || 299 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { 300 if (pixel_clock >= 371250) { 301 /* 5.94Gbps, 3.7125Gbps */ 302 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282); 303 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b); 304 } else if (pixel_clock >= 297000) { 305 /* 2.97Gbps */ 306 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382); 307 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b); 308 } else if (pixel_clock >= 148500) { 309 /* 1.485Gbps */ 310 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362); 311 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b); 312 } else { 313 /* 742.5Mbps, and below */ 314 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142); 315 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b); 316 } 317 } else if (dw_hdmi_is_compatible(dw_hdmi, 318 "amlogic,meson-gxbb-dw-hdmi")) { 319 if (pixel_clock >= 371250) { 320 /* 5.94Gbps, 3.7125Gbps */ 321 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245); 322 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b); 323 } else if (pixel_clock >= 297000) { 324 /* 2.97Gbps */ 325 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283); 326 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b); 327 } else { 328 /* 1.485Gbps, and below */ 329 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); 330 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); 331 } 332 } else if (dw_hdmi_is_compatible(dw_hdmi, 333 "amlogic,meson-g12a-dw-hdmi")) { 334 if (pixel_clock >= 371250) { 335 /* 5.94Gbps, 3.7125Gbps */ 336 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4); 337 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); 338 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b); 339 } else if (pixel_clock >= 297000) { 340 /* 2.97Gbps */ 341 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262); 342 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); 343 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); 344 } else { 345 /* 1.485Gbps, and below */ 346 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242); 347 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); 348 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); 349 } 350 } 351} 352 353static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi) 354{ 355 struct meson_drm *priv = dw_hdmi->priv; 356 357 /* Enable and software reset */ 358 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf); 359 360 mdelay(2); 361 362 /* Enable and unreset */ 363 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe); 364 365 mdelay(2); 366} 367 368static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, 369 const struct drm_display_info *display, 370 const struct drm_display_mode *mode) 371{ 372 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 373 bool is_hdmi2_sink = display->hdmi.scdc.supported; 374 struct meson_drm *priv = dw_hdmi->priv; 375 unsigned int wr_clk = 376 readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); 377 bool mode_is_420 = false; 378 379 DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name, 380 mode->clock > 340000 ? 40 : 10); 381 382 if (drm_mode_is_420_only(display, mode) || 383 (!is_hdmi2_sink && 384 drm_mode_is_420_also(display, mode))) 385 mode_is_420 = true; 386 387 /* Enable clocks */ 388 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); 389 390 /* Bring HDMITX MEM output of power down */ 391 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); 392 393 /* Bring out of reset */ 394 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); 395 396 /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ 397 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 398 0x3, 0x3); 399 400 /* Enable cec_clk and hdcp22_tmdsclk_en */ 401 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 402 0x3 << 4, 0x3 << 4); 403 404 /* Enable normal output to PHY */ 405 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); 406 407 /* TMDS pattern setup */ 408 if (mode->clock > 340000 && !mode_is_420) { 409 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 410 0); 411 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 412 0x03ff03ff); 413 } else { 414 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 415 0x001f001f); 416 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 417 0x001f001f); 418 } 419 420 /* Load TMDS pattern */ 421 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); 422 msleep(20); 423 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); 424 425 /* Setup PHY parameters */ 426 meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420); 427 428 /* Setup PHY */ 429 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 430 0xffff << 16, 0x0390 << 16); 431 432 /* BIT_INVERT */ 433 if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || 434 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || 435 dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) 436 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 437 BIT(17), 0); 438 else 439 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 440 BIT(17), BIT(17)); 441 442 /* Disable clock, fifo, fifo_wr */ 443 regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); 444 445 dw_hdmi_set_high_tmds_clock_ratio(hdmi, display); 446 447 msleep(100); 448 449 /* Reset PHY 3 times in a row */ 450 meson_dw_hdmi_phy_reset(dw_hdmi); 451 meson_dw_hdmi_phy_reset(dw_hdmi); 452 meson_dw_hdmi_phy_reset(dw_hdmi); 453 454 /* Temporary Disable VENC video stream */ 455 if (priv->venc.hdmi_use_enci) 456 writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); 457 else 458 writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); 459 460 /* Temporary Disable HDMI video stream to HDMI-TX */ 461 writel_bits_relaxed(0x3, 0, 462 priv->io_base + _REG(VPU_HDMI_SETTING)); 463 writel_bits_relaxed(0xf << 8, 0, 464 priv->io_base + _REG(VPU_HDMI_SETTING)); 465 466 /* Re-Enable VENC video stream */ 467 if (priv->venc.hdmi_use_enci) 468 writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); 469 else 470 writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); 471 472 /* Push back HDMI clock settings */ 473 writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8), 474 priv->io_base + _REG(VPU_HDMI_SETTING)); 475 476 /* Enable and Select HDMI video source for HDMI-TX */ 477 if (priv->venc.hdmi_use_enci) 478 writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI, 479 priv->io_base + _REG(VPU_HDMI_SETTING)); 480 else 481 writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP, 482 priv->io_base + _REG(VPU_HDMI_SETTING)); 483 484 return 0; 485} 486 487static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, 488 void *data) 489{ 490 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 491 struct meson_drm *priv = dw_hdmi->priv; 492 493 DRM_DEBUG_DRIVER("\n"); 494 495 regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); 496} 497 498static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, 499 void *data) 500{ 501 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 502 503 return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ? 504 connector_status_connected : connector_status_disconnected; 505} 506 507static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, 508 void *data) 509{ 510 struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 511 512 /* Setup HPD Filter */ 513 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, 514 (0xa << 12) | 0xa0); 515 516 /* Clear interrupts */ 517 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, 518 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); 519 520 /* Unmask interrupts */ 521 dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN, 522 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL, 523 HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); 524} 525 526static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = { 527 .init = dw_hdmi_phy_init, 528 .disable = dw_hdmi_phy_disable, 529 .read_hpd = dw_hdmi_read_hpd, 530 .setup_hpd = dw_hdmi_setup_hpd, 531}; 532 533static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) 534{ 535 struct meson_dw_hdmi *dw_hdmi = dev_id; 536 u32 stat; 537 538 stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); 539 dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); 540 541 /* HPD Events, handle in the threaded interrupt handler */ 542 if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { 543 dw_hdmi->irq_stat = stat; 544 return IRQ_WAKE_THREAD; 545 } 546 547 /* HDMI Controller Interrupt */ 548 if (stat & 1) 549 return IRQ_NONE; 550 551 /* TOFIX Handle HDCP Interrupts */ 552 553 return IRQ_HANDLED; 554} 555 556/* Threaded interrupt handler to manage HPD events */ 557static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) 558{ 559 struct meson_dw_hdmi *dw_hdmi = dev_id; 560 u32 stat = dw_hdmi->irq_stat; 561 562 /* HPD Events */ 563 if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { 564 bool hpd_connected = false; 565 566 if (stat & HDMITX_TOP_INTR_HPD_RISE) 567 hpd_connected = true; 568 569 dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected, 570 hpd_connected); 571 572 drm_helper_hpd_irq_event(dw_hdmi->bridge->dev); 573 drm_bridge_hpd_notify(dw_hdmi->bridge, 574 hpd_connected ? connector_status_connected 575 : connector_status_disconnected); 576 } 577 578 return IRQ_HANDLED; 579} 580 581/* DW HDMI Regmap */ 582 583static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, 584 unsigned int *result) 585{ 586 struct meson_dw_hdmi *dw_hdmi = context; 587 588 *result = dw_hdmi->data->dwc_read(dw_hdmi, reg); 589 590 return 0; 591 592} 593 594static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, 595 unsigned int val) 596{ 597 struct meson_dw_hdmi *dw_hdmi = context; 598 599 dw_hdmi->data->dwc_write(dw_hdmi, reg, val); 600 601 return 0; 602} 603 604static const struct regmap_config meson_dw_hdmi_regmap_config = { 605 .reg_bits = 32, 606 .val_bits = 8, 607 .reg_read = meson_dw_hdmi_reg_read, 608 .reg_write = meson_dw_hdmi_reg_write, 609 .max_register = 0x10000, 610 .fast_io = true, 611}; 612 613static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { 614 .top_read = dw_hdmi_top_read, 615 .top_write = dw_hdmi_top_write, 616 .dwc_read = dw_hdmi_dwc_read, 617 .dwc_write = dw_hdmi_dwc_write, 618}; 619 620static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { 621 .top_read = dw_hdmi_g12a_top_read, 622 .top_write = dw_hdmi_g12a_top_write, 623 .dwc_read = dw_hdmi_g12a_dwc_read, 624 .dwc_write = dw_hdmi_g12a_dwc_write, 625}; 626 627static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) 628{ 629 struct meson_drm *priv = meson_dw_hdmi->priv; 630 631 /* Enable clocks */ 632 regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); 633 634 /* Bring HDMITX MEM output of power down */ 635 regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); 636 637 /* Reset HDMITX APB & TX & PHY */ 638 reset_control_reset(meson_dw_hdmi->hdmitx_apb); 639 reset_control_reset(meson_dw_hdmi->hdmitx_ctrl); 640 reset_control_reset(meson_dw_hdmi->hdmitx_phy); 641 642 /* Enable APB3 fail on error */ 643 if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { 644 writel_bits_relaxed(BIT(15), BIT(15), 645 meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); 646 writel_bits_relaxed(BIT(15), BIT(15), 647 meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); 648 } 649 650 /* Bring out of reset */ 651 meson_dw_hdmi->data->top_write(meson_dw_hdmi, 652 HDMITX_TOP_SW_RESET, 0); 653 654 msleep(20); 655 656 meson_dw_hdmi->data->top_write(meson_dw_hdmi, 657 HDMITX_TOP_CLK_CNTL, 0xff); 658 659 /* Enable HDMI-TX Interrupt */ 660 meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, 661 HDMITX_TOP_INTR_CORE); 662 663 meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, 664 HDMITX_TOP_INTR_CORE); 665 666} 667 668static void meson_disable_regulator(void *data) 669{ 670 regulator_disable(data); 671} 672 673static void meson_disable_clk(void *data) 674{ 675 clk_disable_unprepare(data); 676} 677 678static int meson_enable_clk(struct device *dev, char *name) 679{ 680 struct clk *clk; 681 int ret; 682 683 clk = devm_clk_get(dev, name); 684 if (IS_ERR(clk)) { 685 dev_err(dev, "Unable to get %s pclk\n", name); 686 return PTR_ERR(clk); 687 } 688 689 ret = clk_prepare_enable(clk); 690 if (!ret) 691 ret = devm_add_action_or_reset(dev, meson_disable_clk, clk); 692 693 return ret; 694} 695 696static int meson_dw_hdmi_bind(struct device *dev, struct device *master, 697 void *data) 698{ 699 struct platform_device *pdev = to_platform_device(dev); 700 const struct meson_dw_hdmi_data *match; 701 struct meson_dw_hdmi *meson_dw_hdmi; 702 struct drm_device *drm = data; 703 struct meson_drm *priv = drm->dev_private; 704 struct dw_hdmi_plat_data *dw_plat_data; 705 int irq; 706 int ret; 707 708 DRM_DEBUG_DRIVER("\n"); 709 710 match = of_device_get_match_data(&pdev->dev); 711 if (!match) { 712 dev_err(&pdev->dev, "failed to get match data\n"); 713 return -ENODEV; 714 } 715 716 meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), 717 GFP_KERNEL); 718 if (!meson_dw_hdmi) 719 return -ENOMEM; 720 721 meson_dw_hdmi->priv = priv; 722 meson_dw_hdmi->dev = dev; 723 meson_dw_hdmi->data = match; 724 dw_plat_data = &meson_dw_hdmi->dw_plat_data; 725 726 meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi"); 727 if (IS_ERR(meson_dw_hdmi->hdmi_supply)) { 728 if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER) 729 return -EPROBE_DEFER; 730 meson_dw_hdmi->hdmi_supply = NULL; 731 } else { 732 ret = regulator_enable(meson_dw_hdmi->hdmi_supply); 733 if (ret) 734 return ret; 735 ret = devm_add_action_or_reset(dev, meson_disable_regulator, 736 meson_dw_hdmi->hdmi_supply); 737 if (ret) 738 return ret; 739 } 740 741 meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev, 742 "hdmitx_apb"); 743 if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) { 744 dev_err(dev, "Failed to get hdmitx_apb reset\n"); 745 return PTR_ERR(meson_dw_hdmi->hdmitx_apb); 746 } 747 748 meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev, 749 "hdmitx"); 750 if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) { 751 dev_err(dev, "Failed to get hdmitx reset\n"); 752 return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl); 753 } 754 755 meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev, 756 "hdmitx_phy"); 757 if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) { 758 dev_err(dev, "Failed to get hdmitx_phy reset\n"); 759 return PTR_ERR(meson_dw_hdmi->hdmitx_phy); 760 } 761 762 meson_dw_hdmi->hdmitx = devm_platform_ioremap_resource(pdev, 0); 763 if (IS_ERR(meson_dw_hdmi->hdmitx)) 764 return PTR_ERR(meson_dw_hdmi->hdmitx); 765 766 ret = meson_enable_clk(dev, "isfr"); 767 if (ret) 768 return ret; 769 770 ret = meson_enable_clk(dev, "iahb"); 771 if (ret) 772 return ret; 773 774 ret = meson_enable_clk(dev, "venci"); 775 if (ret) 776 return ret; 777 778 dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi, 779 &meson_dw_hdmi_regmap_config); 780 if (IS_ERR(dw_plat_data->regm)) 781 return PTR_ERR(dw_plat_data->regm); 782 783 irq = platform_get_irq(pdev, 0); 784 if (irq < 0) 785 return irq; 786 787 ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq, 788 dw_hdmi_top_thread_irq, IRQF_SHARED, 789 "dw_hdmi_top_irq", meson_dw_hdmi); 790 if (ret) { 791 dev_err(dev, "Failed to request hdmi top irq\n"); 792 return ret; 793 } 794 795 meson_dw_hdmi_init(meson_dw_hdmi); 796 797 /* Bridge / Connector */ 798 799 dw_plat_data->priv_data = meson_dw_hdmi; 800 dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; 801 dw_plat_data->phy_name = "meson_dw_hdmi_phy"; 802 dw_plat_data->phy_data = meson_dw_hdmi; 803 dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; 804 dw_plat_data->ycbcr_420_allowed = true; 805 dw_plat_data->disable_cec = true; 806 dw_plat_data->output_port = 1; 807 808 if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || 809 dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || 810 dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) 811 dw_plat_data->use_drm_infoframe = true; 812 813 platform_set_drvdata(pdev, meson_dw_hdmi); 814 815 meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, &meson_dw_hdmi->dw_plat_data); 816 if (IS_ERR(meson_dw_hdmi->hdmi)) 817 return PTR_ERR(meson_dw_hdmi->hdmi); 818 819 meson_dw_hdmi->bridge = of_drm_find_bridge(pdev->dev.of_node); 820 821 DRM_DEBUG_DRIVER("HDMI controller initialized\n"); 822 823 return 0; 824} 825 826static void meson_dw_hdmi_unbind(struct device *dev, struct device *master, 827 void *data) 828{ 829 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev); 830 831 dw_hdmi_unbind(meson_dw_hdmi->hdmi); 832} 833 834static const struct component_ops meson_dw_hdmi_ops = { 835 .bind = meson_dw_hdmi_bind, 836 .unbind = meson_dw_hdmi_unbind, 837}; 838 839static int __maybe_unused meson_dw_hdmi_pm_suspend(struct device *dev) 840{ 841 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev); 842 843 if (!meson_dw_hdmi) 844 return 0; 845 846 /* Reset TOP */ 847 meson_dw_hdmi->data->top_write(meson_dw_hdmi, 848 HDMITX_TOP_SW_RESET, 0); 849 850 return 0; 851} 852 853static int __maybe_unused meson_dw_hdmi_pm_resume(struct device *dev) 854{ 855 struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev); 856 857 if (!meson_dw_hdmi) 858 return 0; 859 860 meson_dw_hdmi_init(meson_dw_hdmi); 861 862 dw_hdmi_resume(meson_dw_hdmi->hdmi); 863 864 return 0; 865} 866 867static int meson_dw_hdmi_probe(struct platform_device *pdev) 868{ 869 return component_add(&pdev->dev, &meson_dw_hdmi_ops); 870} 871 872static int meson_dw_hdmi_remove(struct platform_device *pdev) 873{ 874 component_del(&pdev->dev, &meson_dw_hdmi_ops); 875 876 return 0; 877} 878 879static const struct dev_pm_ops meson_dw_hdmi_pm_ops = { 880 SET_SYSTEM_SLEEP_PM_OPS(meson_dw_hdmi_pm_suspend, 881 meson_dw_hdmi_pm_resume) 882}; 883 884static const struct of_device_id meson_dw_hdmi_of_table[] = { 885 { .compatible = "amlogic,meson-gxbb-dw-hdmi", 886 .data = &meson_dw_hdmi_gx_data }, 887 { .compatible = "amlogic,meson-gxl-dw-hdmi", 888 .data = &meson_dw_hdmi_gx_data }, 889 { .compatible = "amlogic,meson-gxm-dw-hdmi", 890 .data = &meson_dw_hdmi_gx_data }, 891 { .compatible = "amlogic,meson-g12a-dw-hdmi", 892 .data = &meson_dw_hdmi_g12a_data }, 893 { } 894}; 895MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); 896 897static struct platform_driver meson_dw_hdmi_platform_driver = { 898 .probe = meson_dw_hdmi_probe, 899 .remove = meson_dw_hdmi_remove, 900 .driver = { 901 .name = DRIVER_NAME, 902 .of_match_table = meson_dw_hdmi_of_table, 903 .pm = &meson_dw_hdmi_pm_ops, 904 }, 905}; 906module_platform_driver(meson_dw_hdmi_platform_driver); 907 908MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 909MODULE_DESCRIPTION(DRIVER_DESC); 910MODULE_LICENSE("GPL");