Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY

The Amlogic Meson GXBB/GXL/GXM SoCs embeds a Synopsys DesignWare HDMI TX
Controller with a custom Bridge + PHY around the Controller.

This driver makes uses of all the custom PHY plat data callbacks and enables
the compatible HDMI modes to be configured as a drm_encoder instance.

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

+1066
+6
drivers/gpu/drm/meson/Kconfig
··· 7 7 select DRM_GEM_CMA_HELPER 8 8 select VIDEOMODE_HELPERS 9 9 select REGMAP_MMIO 10 + 11 + config DRM_MESON_DW_HDMI 12 + tristate "HDMI Synopsys Controller support for Amlogic Meson Display" 13 + depends on DRM_MESON 14 + default y if DRM_MESON 15 + select DRM_DW_HDMI
+1
drivers/gpu/drm/meson/Makefile
··· 2 2 meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o 3 3 4 4 obj-$(CONFIG_DRM_MESON) += meson-drm.o 5 + obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
+3
drivers/gpu/drm/meson/meson_drv.h
··· 47 47 48 48 struct { 49 49 unsigned int current_mode; 50 + bool hdmi_repeat; 51 + bool venc_repeat; 52 + bool hdmi_use_enci; 50 53 } venc; 51 54 }; 52 55
+910
drivers/gpu/drm/meson/meson_dw_hdmi.c
··· 1 + /* 2 + * Copyright (C) 2016 BayLibre, SAS 3 + * Author: Neil Armstrong <narmstrong@baylibre.com> 4 + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License as 8 + * published by the Free Software Foundation; either version 2 of the 9 + * License, or (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, but 12 + * WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 + * General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/kernel.h> 21 + #include <linux/module.h> 22 + #include <linux/component.h> 23 + #include <linux/of_graph.h> 24 + #include <linux/reset.h> 25 + #include <linux/clk.h> 26 + 27 + #include <drm/drmP.h> 28 + #include <drm/drm_edid.h> 29 + #include <drm/drm_crtc_helper.h> 30 + #include <drm/drm_atomic_helper.h> 31 + #include <drm/bridge/dw_hdmi.h> 32 + 33 + #include <uapi/linux/media-bus-format.h> 34 + #include <uapi/linux/videodev2.h> 35 + 36 + #include "meson_drv.h" 37 + #include "meson_venc.h" 38 + #include "meson_vclk.h" 39 + #include "meson_dw_hdmi.h" 40 + #include "meson_registers.h" 41 + 42 + #define DRIVER_NAME "meson-dw-hdmi" 43 + #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" 44 + 45 + /* 46 + * HDMI Output is composed of : 47 + * - A Synopsys DesignWare HDMI Controller IP 48 + * - A TOP control block controlling the Clocks and PHY 49 + * - A custom HDMI PHY in order convert video to TMDS signal 50 + * ___________________________________ 51 + * | HDMI TOP |<= HPD 52 + * |___________________________________| 53 + * | | | 54 + * | Synopsys HDMI | HDMI PHY |=> TMDS 55 + * | Controller |________________| 56 + * |___________________________________|<=> DDC 57 + * 58 + * The HDMI TOP block only supports HPD sensing. 59 + * The Synopsys HDMI Controller interrupt is routed 60 + * through the TOP Block interrupt. 61 + * Communication to the TOP Block and the Synopsys 62 + * HDMI Controller is done a pair of addr+read/write 63 + * registers. 64 + * The HDMI PHY is configured by registers in the 65 + * HHI register block. 66 + * 67 + * Pixel data arrives in 4:4:4 format from the VENC 68 + * block and the VPU HDMI mux selects either the ENCI 69 + * encoder for the 576i or 480i formats or the ENCP 70 + * encoder for all the other formats including 71 + * interlaced HD formats. 72 + * The VENC uses a DVI encoder on top of the ENCI 73 + * or ENCP encoders to generate DVI timings for the 74 + * HDMI controller. 75 + * 76 + * GXBB, GXL and GXM embeds the Synopsys DesignWare 77 + * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF 78 + * audio source interfaces. 79 + * 80 + * We handle the following features : 81 + * - HPD Rise & Fall interrupt 82 + * - HDMI Controller Interrupt 83 + * - HDMI PHY Init for 480i to 1080p60 84 + * - VENC & HDMI Clock setup for 480i to 1080p60 85 + * - VENC Mode setup for 480i to 1080p60 86 + * 87 + * What is missing : 88 + * - PHY, Clock and Mode setup for 2k && 4k modes 89 + * - SDDC Scrambling mode for HDMI 2.0a 90 + * - HDCP Setup 91 + * - CEC Management 92 + */ 93 + 94 + /* TOP Block Communication Channel */ 95 + #define HDMITX_TOP_ADDR_REG 0x0 96 + #define HDMITX_TOP_DATA_REG 0x4 97 + #define HDMITX_TOP_CTRL_REG 0x8 98 + 99 + /* Controller Communication Channel */ 100 + #define HDMITX_DWC_ADDR_REG 0x10 101 + #define HDMITX_DWC_DATA_REG 0x14 102 + #define HDMITX_DWC_CTRL_REG 0x18 103 + 104 + /* HHI Registers */ 105 + #define HHI_MEM_PD_REG0 0x100 /* 0x40 */ 106 + #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */ 107 + #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */ 108 + #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ 109 + #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ 110 + #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ 111 + 112 + static DEFINE_SPINLOCK(reg_lock); 113 + 114 + enum meson_venc_source { 115 + MESON_VENC_SOURCE_NONE = 0, 116 + MESON_VENC_SOURCE_ENCI = 1, 117 + MESON_VENC_SOURCE_ENCP = 2, 118 + }; 119 + 120 + struct meson_dw_hdmi { 121 + struct drm_encoder encoder; 122 + struct dw_hdmi_plat_data dw_plat_data; 123 + struct meson_drm *priv; 124 + struct device *dev; 125 + void __iomem *hdmitx; 126 + struct reset_control *hdmitx_apb; 127 + struct reset_control *hdmitx_ctrl; 128 + struct reset_control *hdmitx_phy; 129 + struct clk *hdmi_pclk; 130 + struct clk *venci_clk; 131 + u32 irq_stat; 132 + }; 133 + #define encoder_to_meson_dw_hdmi(x) \ 134 + container_of(x, struct meson_dw_hdmi, encoder) 135 + 136 + static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi, 137 + const char *compat) 138 + { 139 + return of_device_is_compatible(dw_hdmi->dev->of_node, compat); 140 + } 141 + 142 + /* PHY (via TOP bridge) and Controller dedicated register interface */ 143 + 144 + static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, 145 + unsigned int addr) 146 + { 147 + unsigned long flags; 148 + unsigned int data; 149 + 150 + spin_lock_irqsave(&reg_lock, flags); 151 + 152 + /* ADDR must be written twice */ 153 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 154 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 155 + 156 + /* Read needs a second DATA read */ 157 + data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); 158 + data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); 159 + 160 + spin_unlock_irqrestore(&reg_lock, flags); 161 + 162 + return data; 163 + } 164 + 165 + static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, 166 + unsigned int addr, unsigned int data) 167 + { 168 + unsigned long flags; 169 + 170 + spin_lock_irqsave(&reg_lock, flags); 171 + 172 + /* ADDR must be written twice */ 173 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 174 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG); 175 + 176 + /* Write needs single DATA write */ 177 + writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG); 178 + 179 + spin_unlock_irqrestore(&reg_lock, flags); 180 + } 181 + 182 + /* Helper to change specific bits in PHY registers */ 183 + static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, 184 + unsigned int addr, 185 + unsigned int mask, 186 + unsigned int val) 187 + { 188 + unsigned int data = dw_hdmi_top_read(dw_hdmi, addr); 189 + 190 + data &= ~mask; 191 + data |= val; 192 + 193 + dw_hdmi_top_write(dw_hdmi, addr, data); 194 + } 195 + 196 + static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, 197 + unsigned int addr) 198 + { 199 + unsigned long flags; 200 + unsigned int data; 201 + 202 + spin_lock_irqsave(&reg_lock, flags); 203 + 204 + /* ADDR must be written twice */ 205 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 206 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 207 + 208 + /* Read needs a second DATA read */ 209 + data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); 210 + data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); 211 + 212 + spin_unlock_irqrestore(&reg_lock, flags); 213 + 214 + return data; 215 + } 216 + 217 + static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, 218 + unsigned int addr, unsigned int data) 219 + { 220 + unsigned long flags; 221 + 222 + spin_lock_irqsave(&reg_lock, flags); 223 + 224 + /* ADDR must be written twice */ 225 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 226 + writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG); 227 + 228 + /* Write needs single DATA write */ 229 + writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG); 230 + 231 + spin_unlock_irqrestore(&reg_lock, flags); 232 + } 233 + 234 + /* Helper to change specific bits in controller registers */ 235 + static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, 236 + unsigned int addr, 237 + unsigned int mask, 238 + unsigned int val) 239 + { 240 + unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr); 241 + 242 + data &= ~mask; 243 + data |= val; 244 + 245 + dw_hdmi_dwc_write(dw_hdmi, addr, data); 246 + } 247 + 248 + /* Bridge */ 249 + 250 + /* Setup PHY bandwidth modes */ 251 + static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, 252 + struct drm_display_mode *mode) 253 + { 254 + struct meson_drm *priv = dw_hdmi->priv; 255 + unsigned int pixel_clock = mode->clock; 256 + 257 + if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || 258 + dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { 259 + if (pixel_clock >= 371250) { 260 + /* 5.94Gbps, 3.7125Gbps */ 261 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282); 262 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b); 263 + } else if (pixel_clock >= 297000) { 264 + /* 2.97Gbps */ 265 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382); 266 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b); 267 + } else if (pixel_clock >= 148500) { 268 + /* 1.485Gbps */ 269 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362); 270 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b); 271 + } else { 272 + /* 742.5Mbps, and below */ 273 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142); 274 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b); 275 + } 276 + } else if (dw_hdmi_is_compatible(dw_hdmi, 277 + "amlogic,meson-gxbb-dw-hdmi")) { 278 + if (pixel_clock >= 371250) { 279 + /* 5.94Gbps, 3.7125Gbps */ 280 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245); 281 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b); 282 + } else if (pixel_clock >= 297000) { 283 + /* 2.97Gbps */ 284 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283); 285 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b); 286 + } else { 287 + /* 1.485Gbps, and below */ 288 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); 289 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); 290 + } 291 + } 292 + } 293 + 294 + static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi) 295 + { 296 + struct meson_drm *priv = dw_hdmi->priv; 297 + 298 + /* Enable and software reset */ 299 + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf); 300 + 301 + mdelay(2); 302 + 303 + /* Enable and unreset */ 304 + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe); 305 + 306 + mdelay(2); 307 + } 308 + 309 + static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, 310 + struct drm_display_mode *mode) 311 + { 312 + struct meson_drm *priv = dw_hdmi->priv; 313 + int vic = drm_match_cea_mode(mode); 314 + unsigned int vclk_freq; 315 + unsigned int venc_freq; 316 + unsigned int hdmi_freq; 317 + 318 + vclk_freq = mode->clock; 319 + 320 + if (mode->flags & DRM_MODE_FLAG_DBLCLK) 321 + vclk_freq *= 2; 322 + 323 + venc_freq = vclk_freq; 324 + hdmi_freq = vclk_freq; 325 + 326 + if (meson_venc_hdmi_venc_repeat(vic)) 327 + venc_freq *= 2; 328 + 329 + vclk_freq = max(venc_freq, hdmi_freq); 330 + 331 + if (mode->flags & DRM_MODE_FLAG_DBLCLK) 332 + venc_freq /= 2; 333 + 334 + DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n", 335 + vclk_freq, venc_freq, hdmi_freq, 336 + priv->venc.hdmi_use_enci); 337 + 338 + meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq, 339 + venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); 340 + } 341 + 342 + static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, 343 + struct drm_display_mode *mode) 344 + { 345 + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 346 + struct meson_drm *priv = dw_hdmi->priv; 347 + unsigned int wr_clk = 348 + readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); 349 + 350 + DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name); 351 + 352 + /* Enable clocks */ 353 + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); 354 + 355 + /* Bring HDMITX MEM output of power down */ 356 + regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); 357 + 358 + /* Bring out of reset */ 359 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); 360 + 361 + /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ 362 + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 363 + 0x3, 0x3); 364 + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 365 + 0x3 << 4, 0x3 << 4); 366 + 367 + /* Enable normal output to PHY */ 368 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); 369 + 370 + /* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */ 371 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f); 372 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f); 373 + 374 + /* Load TMDS pattern */ 375 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); 376 + msleep(20); 377 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); 378 + 379 + /* Setup PHY parameters */ 380 + meson_hdmi_phy_setup_mode(dw_hdmi, mode); 381 + 382 + /* Setup PHY */ 383 + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 384 + 0xffff << 16, 0x0390 << 16); 385 + 386 + /* BIT_INVERT */ 387 + if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || 388 + dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) 389 + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 390 + BIT(17), 0); 391 + else 392 + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 393 + BIT(17), BIT(17)); 394 + 395 + /* Disable clock, fifo, fifo_wr */ 396 + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); 397 + 398 + msleep(100); 399 + 400 + /* Reset PHY 3 times in a row */ 401 + dw_hdmi_phy_reset(dw_hdmi); 402 + dw_hdmi_phy_reset(dw_hdmi); 403 + dw_hdmi_phy_reset(dw_hdmi); 404 + 405 + /* Temporary Disable VENC video stream */ 406 + if (priv->venc.hdmi_use_enci) 407 + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); 408 + else 409 + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); 410 + 411 + /* Temporary Disable HDMI video stream to HDMI-TX */ 412 + writel_bits_relaxed(0x3, 0, 413 + priv->io_base + _REG(VPU_HDMI_SETTING)); 414 + writel_bits_relaxed(0xf << 8, 0, 415 + priv->io_base + _REG(VPU_HDMI_SETTING)); 416 + 417 + /* Re-Enable VENC video stream */ 418 + if (priv->venc.hdmi_use_enci) 419 + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); 420 + else 421 + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); 422 + 423 + /* Push back HDMI clock settings */ 424 + writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8), 425 + priv->io_base + _REG(VPU_HDMI_SETTING)); 426 + 427 + /* Enable and Select HDMI video source for HDMI-TX */ 428 + if (priv->venc.hdmi_use_enci) 429 + writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI, 430 + priv->io_base + _REG(VPU_HDMI_SETTING)); 431 + else 432 + writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP, 433 + priv->io_base + _REG(VPU_HDMI_SETTING)); 434 + 435 + return 0; 436 + } 437 + 438 + static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, 439 + void *data) 440 + { 441 + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 442 + struct meson_drm *priv = dw_hdmi->priv; 443 + 444 + DRM_DEBUG_DRIVER("\n"); 445 + 446 + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); 447 + } 448 + 449 + static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, 450 + void *data) 451 + { 452 + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 453 + 454 + return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ? 455 + connector_status_connected : connector_status_disconnected; 456 + } 457 + 458 + static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, 459 + void *data) 460 + { 461 + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; 462 + 463 + /* Setup HPD Filter */ 464 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, 465 + (0xa << 12) | 0xa0); 466 + 467 + /* Clear interrupts */ 468 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, 469 + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); 470 + 471 + /* Unmask interrupts */ 472 + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN, 473 + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL, 474 + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); 475 + } 476 + 477 + static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = { 478 + .init = dw_hdmi_phy_init, 479 + .disable = dw_hdmi_phy_disable, 480 + .read_hpd = dw_hdmi_read_hpd, 481 + .setup_hpd = dw_hdmi_setup_hpd, 482 + }; 483 + 484 + static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) 485 + { 486 + struct meson_dw_hdmi *dw_hdmi = dev_id; 487 + u32 stat; 488 + 489 + stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); 490 + dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); 491 + 492 + /* HPD Events, handle in the threaded interrupt handler */ 493 + if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { 494 + dw_hdmi->irq_stat = stat; 495 + return IRQ_WAKE_THREAD; 496 + } 497 + 498 + /* HDMI Controller Interrupt */ 499 + if (stat & 1) 500 + return IRQ_NONE; 501 + 502 + /* TOFIX Handle HDCP Interrupts */ 503 + 504 + return IRQ_HANDLED; 505 + } 506 + 507 + /* Threaded interrupt handler to manage HPD events */ 508 + static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) 509 + { 510 + struct meson_dw_hdmi *dw_hdmi = dev_id; 511 + u32 stat = dw_hdmi->irq_stat; 512 + 513 + /* HPD Events */ 514 + if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { 515 + bool hpd_connected = false; 516 + 517 + if (stat & HDMITX_TOP_INTR_HPD_RISE) 518 + hpd_connected = true; 519 + 520 + dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected, 521 + hpd_connected); 522 + 523 + drm_helper_hpd_irq_event(dw_hdmi->encoder.dev); 524 + } 525 + 526 + return IRQ_HANDLED; 527 + } 528 + 529 + /* TOFIX Enable support for non-vic modes */ 530 + static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector, 531 + struct drm_display_mode *mode) 532 + { 533 + unsigned int vclk_freq; 534 + unsigned int venc_freq; 535 + unsigned int hdmi_freq; 536 + int vic = drm_match_cea_mode(mode); 537 + 538 + DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", 539 + mode->base.id, mode->name, mode->vrefresh, mode->clock, 540 + mode->hdisplay, mode->hsync_start, 541 + mode->hsync_end, mode->htotal, 542 + mode->vdisplay, mode->vsync_start, 543 + mode->vsync_end, mode->vtotal, mode->type, mode->flags); 544 + 545 + /* For now, only accept VIC modes */ 546 + if (!vic) 547 + return MODE_BAD; 548 + 549 + /* For now, filter by supported VIC modes */ 550 + if (!meson_venc_hdmi_supported_vic(vic)) 551 + return MODE_BAD; 552 + 553 + vclk_freq = mode->clock; 554 + 555 + /* 480i/576i needs global pixel doubling */ 556 + if (mode->flags & DRM_MODE_FLAG_DBLCLK) 557 + vclk_freq *= 2; 558 + 559 + venc_freq = vclk_freq; 560 + hdmi_freq = vclk_freq; 561 + 562 + /* VENC double pixels for 1080i and 720p modes */ 563 + if (meson_venc_hdmi_venc_repeat(vic)) 564 + venc_freq *= 2; 565 + 566 + vclk_freq = max(venc_freq, hdmi_freq); 567 + 568 + if (mode->flags & DRM_MODE_FLAG_DBLCLK) 569 + venc_freq /= 2; 570 + 571 + dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, 572 + vclk_freq, venc_freq, hdmi_freq); 573 + 574 + /* Finally filter by configurable vclk frequencies */ 575 + switch (vclk_freq) { 576 + case 54000: 577 + case 74250: 578 + case 148500: 579 + case 297000: 580 + case 594000: 581 + return MODE_OK; 582 + } 583 + 584 + return MODE_CLOCK_RANGE; 585 + } 586 + 587 + /* Encoder */ 588 + 589 + static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder) 590 + { 591 + drm_encoder_cleanup(encoder); 592 + } 593 + 594 + static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = { 595 + .destroy = meson_venc_hdmi_encoder_destroy, 596 + }; 597 + 598 + static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder, 599 + struct drm_crtc_state *crtc_state, 600 + struct drm_connector_state *conn_state) 601 + { 602 + return 0; 603 + } 604 + 605 + static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder) 606 + { 607 + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); 608 + struct meson_drm *priv = dw_hdmi->priv; 609 + 610 + DRM_DEBUG_DRIVER("\n"); 611 + 612 + writel_bits_relaxed(0x3, 0, 613 + priv->io_base + _REG(VPU_HDMI_SETTING)); 614 + 615 + writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); 616 + writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); 617 + } 618 + 619 + static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder) 620 + { 621 + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); 622 + struct meson_drm *priv = dw_hdmi->priv; 623 + 624 + DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); 625 + 626 + if (priv->venc.hdmi_use_enci) 627 + writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); 628 + else 629 + writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); 630 + } 631 + 632 + static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, 633 + struct drm_display_mode *mode, 634 + struct drm_display_mode *adjusted_mode) 635 + { 636 + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); 637 + struct meson_drm *priv = dw_hdmi->priv; 638 + int vic = drm_match_cea_mode(mode); 639 + 640 + DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", 641 + mode->base.id, mode->name, vic); 642 + 643 + /* Should have been filtered */ 644 + if (!vic) 645 + return; 646 + 647 + /* VENC + VENC-DVI Mode setup */ 648 + meson_venc_hdmi_mode_set(priv, vic, mode); 649 + 650 + /* VCLK Set clock */ 651 + dw_hdmi_set_vclk(dw_hdmi, mode); 652 + 653 + /* Setup YUV444 to HDMI-TX, no 10bit diphering */ 654 + writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); 655 + } 656 + 657 + static const struct drm_encoder_helper_funcs 658 + meson_venc_hdmi_encoder_helper_funcs = { 659 + .atomic_check = meson_venc_hdmi_encoder_atomic_check, 660 + .disable = meson_venc_hdmi_encoder_disable, 661 + .enable = meson_venc_hdmi_encoder_enable, 662 + .mode_set = meson_venc_hdmi_encoder_mode_set, 663 + }; 664 + 665 + /* DW HDMI Regmap */ 666 + 667 + static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, 668 + unsigned int *result) 669 + { 670 + *result = dw_hdmi_dwc_read(context, reg); 671 + 672 + return 0; 673 + 674 + } 675 + 676 + static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, 677 + unsigned int val) 678 + { 679 + dw_hdmi_dwc_write(context, reg, val); 680 + 681 + return 0; 682 + } 683 + 684 + static const struct regmap_config meson_dw_hdmi_regmap_config = { 685 + .reg_bits = 32, 686 + .val_bits = 8, 687 + .reg_read = meson_dw_hdmi_reg_read, 688 + .reg_write = meson_dw_hdmi_reg_write, 689 + .max_register = 0x10000, 690 + }; 691 + 692 + static bool meson_hdmi_connector_is_available(struct device *dev) 693 + { 694 + struct device_node *ep, *remote; 695 + 696 + /* HDMI Connector is on the second port, first endpoint */ 697 + ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0); 698 + if (!ep) 699 + return false; 700 + 701 + /* If the endpoint node exists, consider it enabled */ 702 + remote = of_graph_get_remote_port(ep); 703 + if (remote) { 704 + of_node_put(ep); 705 + return true; 706 + } 707 + 708 + of_node_put(ep); 709 + of_node_put(remote); 710 + 711 + return false; 712 + } 713 + 714 + static int meson_dw_hdmi_bind(struct device *dev, struct device *master, 715 + void *data) 716 + { 717 + struct platform_device *pdev = to_platform_device(dev); 718 + struct meson_dw_hdmi *meson_dw_hdmi; 719 + struct drm_device *drm = data; 720 + struct meson_drm *priv = drm->dev_private; 721 + struct dw_hdmi_plat_data *dw_plat_data; 722 + struct drm_encoder *encoder; 723 + struct resource *res; 724 + int irq; 725 + int ret; 726 + 727 + DRM_DEBUG_DRIVER("\n"); 728 + 729 + if (!meson_hdmi_connector_is_available(dev)) { 730 + dev_info(drm->dev, "HDMI Output connector not available\n"); 731 + return -ENODEV; 732 + } 733 + 734 + meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), 735 + GFP_KERNEL); 736 + if (!meson_dw_hdmi) 737 + return -ENOMEM; 738 + 739 + meson_dw_hdmi->priv = priv; 740 + meson_dw_hdmi->dev = dev; 741 + dw_plat_data = &meson_dw_hdmi->dw_plat_data; 742 + encoder = &meson_dw_hdmi->encoder; 743 + 744 + meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev, 745 + "hdmitx_apb"); 746 + if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) { 747 + dev_err(dev, "Failed to get hdmitx_apb reset\n"); 748 + return PTR_ERR(meson_dw_hdmi->hdmitx_apb); 749 + } 750 + 751 + meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev, 752 + "hdmitx"); 753 + if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) { 754 + dev_err(dev, "Failed to get hdmitx reset\n"); 755 + return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl); 756 + } 757 + 758 + meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev, 759 + "hdmitx_phy"); 760 + if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) { 761 + dev_err(dev, "Failed to get hdmitx_phy reset\n"); 762 + return PTR_ERR(meson_dw_hdmi->hdmitx_phy); 763 + } 764 + 765 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 766 + meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res); 767 + if (IS_ERR(meson_dw_hdmi->hdmitx)) 768 + return PTR_ERR(meson_dw_hdmi->hdmitx); 769 + 770 + meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr"); 771 + if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) { 772 + dev_err(dev, "Unable to get HDMI pclk\n"); 773 + return PTR_ERR(meson_dw_hdmi->hdmi_pclk); 774 + } 775 + clk_prepare_enable(meson_dw_hdmi->hdmi_pclk); 776 + 777 + meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci"); 778 + if (IS_ERR(meson_dw_hdmi->venci_clk)) { 779 + dev_err(dev, "Unable to get venci clk\n"); 780 + return PTR_ERR(meson_dw_hdmi->venci_clk); 781 + } 782 + clk_prepare_enable(meson_dw_hdmi->venci_clk); 783 + 784 + dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi, 785 + &meson_dw_hdmi_regmap_config); 786 + if (IS_ERR(dw_plat_data->regm)) 787 + return PTR_ERR(dw_plat_data->regm); 788 + 789 + irq = platform_get_irq(pdev, 0); 790 + if (irq < 0) { 791 + dev_err(dev, "Failed to get hdmi top irq\n"); 792 + return irq; 793 + } 794 + 795 + ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq, 796 + dw_hdmi_top_thread_irq, IRQF_SHARED, 797 + "dw_hdmi_top_irq", meson_dw_hdmi); 798 + if (ret) { 799 + dev_err(dev, "Failed to request hdmi top irq\n"); 800 + return ret; 801 + } 802 + 803 + /* Encoder */ 804 + 805 + drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs); 806 + 807 + ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs, 808 + DRM_MODE_ENCODER_TMDS, "meson_hdmi"); 809 + if (ret) { 810 + dev_err(priv->dev, "Failed to init HDMI encoder\n"); 811 + return ret; 812 + } 813 + 814 + encoder->possible_crtcs = BIT(0); 815 + 816 + DRM_DEBUG_DRIVER("encoder initialized\n"); 817 + 818 + /* Enable clocks */ 819 + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); 820 + 821 + /* Bring HDMITX MEM output of power down */ 822 + regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); 823 + 824 + /* Reset HDMITX APB & TX & PHY */ 825 + reset_control_reset(meson_dw_hdmi->hdmitx_apb); 826 + reset_control_reset(meson_dw_hdmi->hdmitx_ctrl); 827 + reset_control_reset(meson_dw_hdmi->hdmitx_phy); 828 + 829 + /* Enable APB3 fail on error */ 830 + writel_bits_relaxed(BIT(15), BIT(15), 831 + meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); 832 + writel_bits_relaxed(BIT(15), BIT(15), 833 + meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); 834 + 835 + /* Bring out of reset */ 836 + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); 837 + 838 + msleep(20); 839 + 840 + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); 841 + 842 + /* Enable HDMI-TX Interrupt */ 843 + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, 844 + HDMITX_TOP_INTR_CORE); 845 + 846 + dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, 847 + HDMITX_TOP_INTR_CORE); 848 + 849 + /* Bridge / Connector */ 850 + 851 + dw_plat_data->mode_valid = dw_hdmi_mode_valid; 852 + dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; 853 + dw_plat_data->phy_name = "meson_dw_hdmi_phy"; 854 + dw_plat_data->phy_data = meson_dw_hdmi; 855 + dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; 856 + dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; 857 + 858 + ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data); 859 + if (ret) 860 + return ret; 861 + 862 + DRM_DEBUG_DRIVER("HDMI controller initialized\n"); 863 + 864 + return 0; 865 + } 866 + 867 + static void meson_dw_hdmi_unbind(struct device *dev, struct device *master, 868 + void *data) 869 + { 870 + dw_hdmi_unbind(dev); 871 + } 872 + 873 + static const struct component_ops meson_dw_hdmi_ops = { 874 + .bind = meson_dw_hdmi_bind, 875 + .unbind = meson_dw_hdmi_unbind, 876 + }; 877 + 878 + static int meson_dw_hdmi_probe(struct platform_device *pdev) 879 + { 880 + return component_add(&pdev->dev, &meson_dw_hdmi_ops); 881 + } 882 + 883 + static int meson_dw_hdmi_remove(struct platform_device *pdev) 884 + { 885 + component_del(&pdev->dev, &meson_dw_hdmi_ops); 886 + 887 + return 0; 888 + } 889 + 890 + static const struct of_device_id meson_dw_hdmi_of_table[] = { 891 + { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, 892 + { .compatible = "amlogic,meson-gxl-dw-hdmi" }, 893 + { .compatible = "amlogic,meson-gxm-dw-hdmi" }, 894 + { } 895 + }; 896 + MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); 897 + 898 + static struct platform_driver meson_dw_hdmi_platform_driver = { 899 + .probe = meson_dw_hdmi_probe, 900 + .remove = meson_dw_hdmi_remove, 901 + .driver = { 902 + .name = DRIVER_NAME, 903 + .of_match_table = meson_dw_hdmi_of_table, 904 + }, 905 + }; 906 + module_platform_driver(meson_dw_hdmi_platform_driver); 907 + 908 + MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 909 + MODULE_DESCRIPTION(DRIVER_DESC); 910 + MODULE_LICENSE("GPL");
+146
drivers/gpu/drm/meson/meson_dw_hdmi.h
··· 1 + /* 2 + * Copyright (C) 2016 BayLibre, SAS 3 + * Author: Neil Armstrong <narmstrong@baylibre.com> 4 + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License as 8 + * published by the Free Software Foundation; either version 2 of the 9 + * License, or (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, but 12 + * WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 + * General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef __MESON_DW_HDMI_H 21 + #define __MESON_DW_HDMI_H 22 + 23 + /* 24 + * Bit 7 RW Reserved. Default 1. 25 + * Bit 6 RW Reserved. Default 1. 26 + * Bit 5 RW Reserved. Default 1. 27 + * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. 28 + * Default 1. 29 + * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; 30 + * 0=Release from reset. 31 + * Default 1. 32 + * Bit 2 RW sw_reset_mem: KSV/REVOC mem. 1=Apply reset; 0=Release from reset. 33 + * Default 1. 34 + * Bit 1 RW sw_reset_rnd: random number interface to HDCP. 1=Apply reset; 35 + * 0=Release from reset. Default 1. 36 + * Bit 0 RW sw_reset_core: connects to IP's ~irstz. 1=Apply reset; 37 + * 0=Release from reset. Default 1. 38 + */ 39 + #define HDMITX_TOP_SW_RESET (0x000) 40 + 41 + /* 42 + * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. 43 + * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. 44 + * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. 45 + * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. 46 + * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. 47 + * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. 48 + * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. 49 + * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. 50 + * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. 51 + * Bit 0 RW pixel_clk_en: 1=enable pixel_clk; 0=disable. Default 0. 52 + */ 53 + #define HDMITX_TOP_CLK_CNTL (0x001) 54 + 55 + /* 56 + * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. 57 + * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. 58 + */ 59 + #define HDMITX_TOP_HPD_FILTER (0x002) 60 + 61 + /* 62 + * intr_maskn: MASK_N, one bit per interrupt source. 63 + * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. 64 + * [ 4] hdcp22_rndnum_err 65 + * [ 3] nonce_rfrsh_rise 66 + * [ 2] hpd_fall_intr 67 + * [ 1] hpd_rise_intr 68 + * [ 0] core_intr 69 + */ 70 + #define HDMITX_TOP_INTR_MASKN (0x003) 71 + 72 + /* 73 + * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt 74 + * bit, read back the interrupt status. 75 + * Bit 31 R IP interrupt status 76 + * Bit 2 RW hpd_fall 77 + * Bit 1 RW hpd_rise 78 + * Bit 0 RW IP interrupt 79 + */ 80 + #define HDMITX_TOP_INTR_STAT (0x004) 81 + 82 + /* 83 + * [4] hdcp22_rndnum_err 84 + * [3] nonce_rfrsh_rise 85 + * [2] hpd_fall 86 + * [1] hpd_rise 87 + * [0] core_intr_rise 88 + */ 89 + #define HDMITX_TOP_INTR_STAT_CLR (0x005) 90 + 91 + #define HDMITX_TOP_INTR_CORE BIT(0) 92 + #define HDMITX_TOP_INTR_HPD_RISE BIT(1) 93 + #define HDMITX_TOP_INTR_HPD_FALL BIT(2) 94 + 95 + /* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; 96 + * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. 97 + * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern 98 + * every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0. 99 + * Bit 8 RW shift_pttn_en: 1= Enable shift pattern generator; 0=Disable. 100 + * Default 0. 101 + * Bit 4: 3 RW prbs_pttn_mode: 0=PRBS11; 1=PRBS15; 2=PRBS7; 3=PRBS31. Default 0. 102 + * Bit 2: 1 RW prbs_pttn_width: 0=idle; 1=output 8-bit pattern; 103 + * 2=Output 1-bit pattern; 3=output 10-bit pattern. Default 0. 104 + * Bit 0 RW prbs_pttn_en: 1=Enable PRBS generator; 0=Disable. Default 0. 105 + */ 106 + #define HDMITX_TOP_BIST_CNTL (0x006) 107 + 108 + /* Bit 29:20 RW shift_pttn_data[59:50]. Default 0. */ 109 + /* Bit 19:10 RW shift_pttn_data[69:60]. Default 0. */ 110 + /* Bit 9: 0 RW shift_pttn_data[79:70]. Default 0. */ 111 + #define HDMITX_TOP_SHIFT_PTTN_012 (0x007) 112 + 113 + /* Bit 29:20 RW shift_pttn_data[29:20]. Default 0. */ 114 + /* Bit 19:10 RW shift_pttn_data[39:30]. Default 0. */ 115 + /* Bit 9: 0 RW shift_pttn_data[49:40]. Default 0. */ 116 + #define HDMITX_TOP_SHIFT_PTTN_345 (0x008) 117 + 118 + /* Bit 19:10 RW shift_pttn_data[ 9: 0]. Default 0. */ 119 + /* Bit 9: 0 RW shift_pttn_data[19:10]. Default 0. */ 120 + #define HDMITX_TOP_SHIFT_PTTN_67 (0x009) 121 + 122 + /* Bit 25:16 RW tmds_clk_pttn[19:10]. Default 0. */ 123 + /* Bit 9: 0 RW tmds_clk_pttn[ 9: 0]. Default 0. */ 124 + #define HDMITX_TOP_TMDS_CLK_PTTN_01 (0x00A) 125 + 126 + /* Bit 25:16 RW tmds_clk_pttn[39:30]. Default 0. */ 127 + /* Bit 9: 0 RW tmds_clk_pttn[29:20]. Default 0. */ 128 + #define HDMITX_TOP_TMDS_CLK_PTTN_23 (0x00B) 129 + 130 + /* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, 131 + * used when TMDS CLK rate = TMDS character rate /4. Default 0. 132 + * Bit 0 R Reserved. Default 0. 133 + * [ 1] shift_tmds_clk_pttn 134 + * [ 0] load_tmds_clk_pttn 135 + */ 136 + #define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (0x00C) 137 + 138 + /* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM 139 + * failure, write 1 to clear the failure flag. Default 0. 140 + */ 141 + #define HDMITX_TOP_REVOCMEM_STAT (0x00D) 142 + 143 + /* Bit 0 R filtered HPD status. */ 144 + #define HDMITX_TOP_STAT0 (0x00E) 145 + 146 + #endif /* __MESON_DW_HDMI_H */