1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 BayLibre, SAS 4 * Author: Jorge Ramirez-Ortiz <jramirez@baylibre.com> 5 */ 6 7 #include <common.h> 8 #include <display.h> 9 #include <dm.h> 10 #include <edid.h> 11 #include <asm/io.h> 12 #include <dw_hdmi.h> 13 #include <dm/device-internal.h> 14 #include <dm/uclass-internal.h> 15 #include <power/regulator.h> 16 #include <clk.h> 17 #include <linux/delay.h> 18 #include <reset.h> 19 #include <media_bus_format.h> 20 #include "meson_dw_hdmi.h" 21 #include "meson_vpu.h" 22 23 /* TOP Block Communication Channel */ 24 #define HDMITX_TOP_ADDR_REG 0x0 25 #define HDMITX_TOP_DATA_REG 0x4 26 #define HDMITX_TOP_CTRL_REG 0x8 27 28 /* Controller Communication Channel */ 29 #define HDMITX_DWC_ADDR_REG 0x10 30 #define HDMITX_DWC_DATA_REG 0x14 31 #define HDMITX_DWC_CTRL_REG 0x18 32 33 /* HHI Registers */ 34 #define HHI_MEM_PD_REG0 0x100 /* 0x40 */ 35 #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */ 36 #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */ 37 #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ 38 #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ 39 #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ 40 41 struct meson_dw_hdmi { 42 struct udevice *dev; 43 struct dw_hdmi hdmi; 44 void __iomem *hhi_base; 45 }; 46 47 enum hdmi_compatible { 48 HDMI_COMPATIBLE_GXBB = 0, 49 HDMI_COMPATIBLE_GXL = 1, 50 HDMI_COMPATIBLE_GXM = 2, 51 }; 52 53 static inline bool meson_hdmi_is_compatible(struct meson_dw_hdmi *priv, 54 enum hdmi_compatible family) 55 { 56 enum hdmi_compatible compat = dev_get_driver_data(priv->dev); 57 58 return compat == family; 59 } 60 61 static unsigned int dw_hdmi_top_read(struct dw_hdmi *hdmi, unsigned int addr) 62 { 63 unsigned int data; 64 65 /* ADDR must be written twice */ 66 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); 67 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); 68 69 /* Read needs a second DATA read */ 70 data = readl(hdmi->ioaddr + HDMITX_TOP_DATA_REG); 71 data = readl(hdmi->ioaddr + HDMITX_TOP_DATA_REG); 72 73 return data; 74 } 75 76 static inline void dw_hdmi_top_write(struct dw_hdmi *hdmi, 77 unsigned int addr, unsigned int data) 78 { 79 /* ADDR must be written twice */ 80 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); 81 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); 82 83 /* Write needs single DATA write */ 84 writel(data, hdmi->ioaddr + HDMITX_TOP_DATA_REG); 85 } 86 87 static inline void dw_hdmi_top_write_bits(struct dw_hdmi *hdmi, 88 unsigned int addr, 89 unsigned int mask, 90 unsigned int val) 91 { 92 unsigned int data = dw_hdmi_top_read(hdmi, addr); 93 94 data &= ~mask; 95 data |= val; 96 dw_hdmi_top_write(hdmi, addr, data); 97 } 98 99 static u8 dw_hdmi_dwc_read(struct dw_hdmi *hdmi, int addr) 100 { 101 unsigned int data; 102 103 /* ADDR must be written twice */ 104 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG); 105 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG); 106 107 /* Read needs a second DATA read */ 108 data = readl(hdmi->ioaddr + HDMITX_DWC_DATA_REG); 109 data = readl(hdmi->ioaddr + HDMITX_DWC_DATA_REG); 110 111 return data; 112 } 113 114 static inline void dw_hdmi_dwc_write(struct dw_hdmi *hdmi, u8 data, int addr) 115 { 116 /* ADDR must be written twice */ 117 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG); 118 writel(addr & 0xffff, hdmi->ioaddr + HDMITX_DWC_ADDR_REG); 119 120 /* Write needs single DATA write */ 121 writel(data, hdmi->ioaddr + HDMITX_DWC_DATA_REG); 122 } 123 124 static inline void dw_hdmi_dwc_write_bits(struct dw_hdmi *hdmi, 125 unsigned int addr, 126 unsigned int mask, 127 unsigned int val) 128 { 129 u8 data = dw_hdmi_dwc_read(hdmi, addr); 130 131 data &= ~mask; 132 data |= val; 133 134 dw_hdmi_dwc_write(hdmi, data, addr); 135 } 136 137 static inline void dw_hdmi_hhi_write(struct meson_dw_hdmi *priv, 138 unsigned int addr, unsigned int data) 139 { 140 hhi_write(addr, data); 141 } 142 143 __attribute__((unused)) 144 static unsigned int dw_hdmi_hhi_read(struct meson_dw_hdmi *priv, 145 unsigned int addr) 146 { 147 return hhi_read(addr); 148 } 149 150 static inline void dw_hdmi_hhi_update_bits(struct meson_dw_hdmi *priv, 151 unsigned int addr, 152 unsigned int mask, 153 unsigned int val) 154 { 155 hhi_update_bits(addr, mask, val); 156 } 157 158 static int meson_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size) 159 { 160 #if defined DEBUG 161 struct display_timing timing; 162 int panel_bits_per_colour; 163 #endif 164 struct meson_dw_hdmi *priv = dev_get_priv(dev); 165 int ret; 166 167 ret = dw_hdmi_read_edid(&priv->hdmi, buf, buf_size); 168 169 #if defined DEBUG 170 if (!ret) 171 return ret; 172 173 edid_print_info((struct edid1_info *)buf); 174 edid_get_timing(buf, ret, &timing, &panel_bits_per_colour); 175 debug("Display timing:\n"); 176 debug(" hactive %04d, hfrontp %04d, hbackp %04d hsync %04d\n" 177 " vactive %04d, vfrontp %04d, vbackp %04d vsync %04d\n", 178 timing.hactive.typ, timing.hfront_porch.typ, 179 timing.hback_porch.typ, timing.hsync_len.typ, 180 timing.vactive.typ, timing.vfront_porch.typ, 181 timing.vback_porch.typ, timing.vsync_len.typ); 182 debug(" flags: "); 183 if (timing.flags & DISPLAY_FLAGS_INTERLACED) 184 debug("interlaced "); 185 if (timing.flags & DISPLAY_FLAGS_DOUBLESCAN) 186 debug("doublescan "); 187 if (timing.flags & DISPLAY_FLAGS_DOUBLECLK) 188 debug("doubleclk "); 189 if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW) 190 debug("hsync_low "); 191 if (timing.flags & DISPLAY_FLAGS_HSYNC_HIGH) 192 debug("hsync_high "); 193 if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW) 194 debug("vsync_low "); 195 if (timing.flags & DISPLAY_FLAGS_VSYNC_HIGH) 196 debug("vsync_high "); 197 debug("\n"); 198 #endif 199 200 return ret; 201 } 202 203 static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *priv) 204 { 205 /* Enable and software reset */ 206 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 0xf, 0xf); 207 208 mdelay(2); 209 210 /* Enable and unreset */ 211 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 0xf, 0xe); 212 213 mdelay(2); 214 } 215 216 static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv, 217 uint pixel_clock) 218 { 219 pixel_clock = pixel_clock / 1000; 220 221 if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXL) || 222 meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXM)) { 223 if (pixel_clock >= 371250) { 224 /* 5.94Gbps, 3.7125Gbps */ 225 hhi_write(HHI_HDMI_PHY_CNTL0, 0x333d3282); 226 hhi_write(HHI_HDMI_PHY_CNTL3, 0x2136315b); 227 } else if (pixel_clock >= 297000) { 228 /* 2.97Gbps */ 229 hhi_write(HHI_HDMI_PHY_CNTL0, 0x33303382); 230 hhi_write(HHI_HDMI_PHY_CNTL3, 0x2036315b); 231 } else if (pixel_clock >= 148500) { 232 /* 1.485Gbps */ 233 hhi_write(HHI_HDMI_PHY_CNTL0, 0x33303362); 234 hhi_write(HHI_HDMI_PHY_CNTL3, 0x2016315b); 235 } else { 236 /* 742.5Mbps, and below */ 237 hhi_write(HHI_HDMI_PHY_CNTL0, 0x33604142); 238 hhi_write(HHI_HDMI_PHY_CNTL3, 0x0016315b); 239 } 240 } else { 241 if (pixel_clock >= 371250) { 242 /* 5.94Gbps, 3.7125Gbps */ 243 hhi_write(HHI_HDMI_PHY_CNTL0, 0x33353245); 244 hhi_write(HHI_HDMI_PHY_CNTL3, 0x2100115b); 245 } else if (pixel_clock >= 297000) { 246 /* 2.97Gbps */ 247 hhi_write(HHI_HDMI_PHY_CNTL0, 0x33634283); 248 hhi_write(HHI_HDMI_PHY_CNTL3, 0xb000115b); 249 } else { 250 /* 1.485Gbps, and below */ 251 hhi_write(HHI_HDMI_PHY_CNTL0, 0x33632122); 252 hhi_write(HHI_HDMI_PHY_CNTL3, 0x2000115b); 253 } 254 } 255 } 256 257 static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock) 258 { 259 struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi, 260 hdmi); 261 /* Enable clocks */ 262 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); 263 264 /* Bring HDMITX MEM output of power down */ 265 dw_hdmi_hhi_update_bits(priv, HHI_MEM_PD_REG0, 0xff << 8, 0); 266 267 /* Bring out of reset */ 268 dw_hdmi_top_write(hdmi, HDMITX_TOP_SW_RESET, 0); 269 270 /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ 271 dw_hdmi_top_write_bits(hdmi, HDMITX_TOP_CLK_CNTL, 0x3, 0x3); 272 dw_hdmi_top_write_bits(hdmi, HDMITX_TOP_CLK_CNTL, 0x3 << 4, 0x3 << 4); 273 274 /* Enable normal output to PHY */ 275 dw_hdmi_top_write(hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); 276 277 /* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */ 278 dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f); 279 dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f); 280 281 /* Load TMDS pattern */ 282 dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); 283 mdelay(20); 284 dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); 285 286 /* Setup PHY parameters */ 287 meson_dw_hdmi_phy_setup_mode(priv, pixel_clock); 288 289 /* Setup PHY */ 290 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 291 0xffff << 16, 0x0390 << 16); 292 293 /* BIT_INVERT */ 294 if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXL) || 295 meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXM)) 296 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, BIT(17), 0); 297 else 298 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 299 BIT(17), BIT(17)); 300 301 /* Disable clock, fifo, fifo_wr */ 302 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, 0xf, 0); 303 304 mdelay(100); 305 306 /* Reset PHY 3 times in a row */ 307 meson_dw_hdmi_phy_reset(priv); 308 meson_dw_hdmi_phy_reset(priv); 309 meson_dw_hdmi_phy_reset(priv); 310 311 return 0; 312 } 313 314 static int meson_dw_hdmi_enable(struct udevice *dev, int panel_bpp, 315 const struct display_timing *edid) 316 { 317 struct meson_dw_hdmi *priv = dev_get_priv(dev); 318 319 /* will back into meson_dw_hdmi_phy_init */ 320 return dw_hdmi_enable(&priv->hdmi, edid); 321 } 322 323 static int meson_dw_hdmi_wait_hpd(struct dw_hdmi *hdmi) 324 { 325 int i; 326 327 /* Poll 1 second for HPD signal */ 328 for (i = 0; i < 10; ++i) { 329 if (dw_hdmi_top_read(hdmi, HDMITX_TOP_STAT0)) 330 return 0; 331 332 mdelay(100); 333 } 334 335 return -ETIMEDOUT; 336 } 337 338 static int meson_dw_hdmi_probe(struct udevice *dev) 339 { 340 struct meson_dw_hdmi *priv = dev_get_priv(dev); 341 struct reset_ctl_bulk resets; 342 struct clk_bulk clocks; 343 struct udevice *supply; 344 int ret; 345 346 priv->dev = dev; 347 348 priv->hdmi.ioaddr = (ulong)dev_remap_addr_index(dev, 0); 349 if (!priv->hdmi.ioaddr) 350 return -EINVAL; 351 352 priv->hhi_base = dev_remap_addr_index(dev, 1); 353 if (!priv->hhi_base) 354 return -EINVAL; 355 356 priv->hdmi.hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; 357 priv->hdmi.hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_YUV8_1X24; 358 priv->hdmi.phy_set = meson_dw_hdmi_phy_init; 359 priv->hdmi.write_reg = dw_hdmi_dwc_write; 360 priv->hdmi.read_reg = dw_hdmi_dwc_read; 361 priv->hdmi.i2c_clk_high = 0x67; 362 priv->hdmi.i2c_clk_low = 0x78; 363 364 ret = device_get_supply_regulator(dev, "hdmi-supply", &supply); 365 if (ret) 366 return ret; 367 368 ret = regulator_set_enable(supply, true); 369 if (ret) 370 return ret; 371 372 ret = reset_get_bulk(dev, &resets); 373 if (ret) 374 return ret; 375 376 ret = clk_get_bulk(dev, &clocks); 377 if (ret) 378 return ret; 379 380 ret = clk_enable_bulk(&clocks); 381 if (ret) 382 return ret; 383 384 /* Enable clocks */ 385 dw_hdmi_hhi_update_bits(priv, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); 386 387 /* Bring HDMITX MEM output of power down */ 388 dw_hdmi_hhi_update_bits(priv, HHI_MEM_PD_REG0, 0xff << 8, 0); 389 390 /* Reset HDMITX APB & TX & PHY: cycle needed for EDID */ 391 ret = reset_deassert_bulk(&resets); 392 if (ret) 393 return ret; 394 395 ret = reset_assert_bulk(&resets); 396 if (ret) 397 return ret; 398 399 ret = reset_deassert_bulk(&resets); 400 if (ret) 401 return ret; 402 403 /* Enable APB3 fail on error */ 404 writel_bits(BIT(15), BIT(15), priv->hdmi.ioaddr + HDMITX_TOP_CTRL_REG); 405 writel_bits(BIT(15), BIT(15), priv->hdmi.ioaddr + HDMITX_DWC_CTRL_REG); 406 407 /* Bring out of reset */ 408 dw_hdmi_top_write(&priv->hdmi, HDMITX_TOP_SW_RESET, 0); 409 mdelay(20); 410 dw_hdmi_top_write(&priv->hdmi, HDMITX_TOP_CLK_CNTL, 0xff); 411 412 dw_hdmi_init(&priv->hdmi); 413 dw_hdmi_phy_init(&priv->hdmi); 414 415 /* wait for connector */ 416 ret = meson_dw_hdmi_wait_hpd(&priv->hdmi); 417 if (ret) 418 debug("hdmi can not get hpd signal\n"); 419 420 return ret; 421 } 422 423 static const struct dm_display_ops meson_dw_hdmi_ops = { 424 .read_edid = meson_dw_hdmi_read_edid, 425 .enable = meson_dw_hdmi_enable, 426 }; 427 428 static const struct udevice_id meson_dw_hdmi_ids[] = { 429 { .compatible = "amlogic,meson-gxbb-dw-hdmi", 430 .data = HDMI_COMPATIBLE_GXBB }, 431 { .compatible = "amlogic,meson-gxl-dw-hdmi", 432 .data = HDMI_COMPATIBLE_GXL }, 433 { .compatible = "amlogic,meson-gxm-dw-hdmi", 434 .data = HDMI_COMPATIBLE_GXM }, 435 { } 436 }; 437 438 U_BOOT_DRIVER(meson_dw_hdmi) = { 439 .name = "meson_dw_hdmi", 440 .id = UCLASS_DISPLAY, 441 .of_match = meson_dw_hdmi_ids, 442 .ops = &meson_dw_hdmi_ops, 443 .probe = meson_dw_hdmi_probe, 444 .priv_auto_alloc_size = sizeof(struct meson_dw_hdmi), 445 }; 446