1 /*- 2 * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 /* 31 * HDMI core module 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/module.h> 38 #include <sys/bus.h> 39 #include <sys/rman.h> 40 41 #include <dev/ofw/ofw_bus.h> 42 #include <dev/ofw/ofw_bus_subr.h> 43 44 #include <machine/bus.h> 45 46 #include <dev/videomode/videomode.h> 47 #include <dev/videomode/edidvar.h> 48 49 #include <dev/iicbus/iicbus.h> 50 #include <dev/iicbus/iiconf.h> 51 52 #include <arm/freescale/imx/imx_ccmvar.h> 53 #include <arm/freescale/imx/imx_iomuxvar.h> 54 #include <arm/freescale/imx/imx_iomuxreg.h> 55 #include <arm/freescale/imx/imx6_hdmireg.h> 56 57 #include "hdmi_if.h" 58 59 #define I2C_DDC_ADDR (0x50 << 1) 60 #define EDID_LENGTH 0x80 61 62 struct imx_hdmi_softc { 63 device_t sc_dev; 64 struct resource *sc_mem_res; 65 int sc_mem_rid; 66 struct intr_config_hook sc_mode_hook; 67 struct videomode sc_mode; 68 uint8_t *sc_edid; 69 uint8_t sc_edid_len; 70 phandle_t sc_i2c_xref; 71 }; 72 73 static struct ofw_compat_data compat_data[] = { 74 {"fsl,imx6dl-hdmi", 1}, 75 {"fsl,imx6q-hdmi", 1}, 76 {NULL, 0} 77 }; 78 79 static inline uint8_t 80 RD1(struct imx_hdmi_softc *sc, bus_size_t off) 81 { 82 83 return (bus_read_1(sc->sc_mem_res, off)); 84 } 85 86 static inline void 87 WR1(struct imx_hdmi_softc *sc, bus_size_t off, uint8_t val) 88 { 89 90 bus_write_1(sc->sc_mem_res, off, val); 91 } 92 93 static void 94 imx_hdmi_phy_wait_i2c_done(struct imx_hdmi_softc *sc, int msec) 95 { 96 uint8_t val; 97 98 val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) & 99 (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR); 100 while (val == 0) { 101 pause("HDMI_PHY", hz/100); 102 msec -= 10; 103 if (msec <= 0) 104 return; 105 val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) & 106 (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR); 107 } 108 } 109 110 static void 111 imx_hdmi_phy_i2c_write(struct imx_hdmi_softc *sc, unsigned short data, 112 unsigned char addr) 113 { 114 115 /* clear DONE and ERROR flags */ 116 WR1(sc, HDMI_IH_I2CMPHY_STAT0, 117 HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR); 118 WR1(sc, HDMI_PHY_I2CM_ADDRESS_ADDR, addr); 119 WR1(sc, HDMI_PHY_I2CM_DATAO_1_ADDR, ((data >> 8) & 0xff)); 120 WR1(sc, HDMI_PHY_I2CM_DATAO_0_ADDR, ((data >> 0) & 0xff)); 121 WR1(sc, HDMI_PHY_I2CM_OPERATION_ADDR, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE); 122 imx_hdmi_phy_wait_i2c_done(sc, 1000); 123 } 124 125 static void 126 imx_hdmi_disable_overflow_interrupts(struct imx_hdmi_softc *sc) 127 { 128 WR1(sc, HDMI_IH_MUTE_FC_STAT2, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK); 129 WR1(sc, HDMI_FC_MASK2, 130 HDMI_FC_MASK2_LOW_PRI | HDMI_FC_MASK2_HIGH_PRI); 131 } 132 133 static void 134 imx_hdmi_av_composer(struct imx_hdmi_softc *sc) 135 { 136 uint8_t inv_val; 137 int is_dvi; 138 int hblank, vblank, hsync_len, hbp, vbp; 139 140 /* Set up HDMI_FC_INVIDCONF */ 141 inv_val = ((sc->sc_mode.flags & VID_NVSYNC) ? 142 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW : 143 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH); 144 145 inv_val |= ((sc->sc_mode.flags & VID_NHSYNC) ? 146 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW : 147 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH); 148 149 inv_val |= HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH; 150 151 inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ? 152 HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH : 153 HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW); 154 155 inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ? 156 HDMI_FC_INVIDCONF_IN_I_P_INTERLACED : 157 HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE); 158 159 /* TODO: implement HDMI part */ 160 is_dvi = 1; 161 inv_val |= (is_dvi ? 162 HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE : 163 HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE); 164 165 WR1(sc, HDMI_FC_INVIDCONF, inv_val); 166 167 /* Set up horizontal active pixel region width */ 168 WR1(sc, HDMI_FC_INHACTV1, sc->sc_mode.hdisplay >> 8); 169 WR1(sc, HDMI_FC_INHACTV0, sc->sc_mode.hdisplay); 170 171 /* Set up vertical blanking pixel region width */ 172 WR1(sc, HDMI_FC_INVACTV1, sc->sc_mode.vdisplay >> 8); 173 WR1(sc, HDMI_FC_INVACTV0, sc->sc_mode.vdisplay); 174 175 /* Set up horizontal blanking pixel region width */ 176 hblank = sc->sc_mode.htotal - sc->sc_mode.hdisplay; 177 WR1(sc, HDMI_FC_INHBLANK1, hblank >> 8); 178 WR1(sc, HDMI_FC_INHBLANK0, hblank); 179 180 /* Set up vertical blanking pixel region width */ 181 vblank = sc->sc_mode.vtotal - sc->sc_mode.vdisplay; 182 WR1(sc, HDMI_FC_INVBLANK, vblank); 183 184 /* Set up HSYNC active edge delay width (in pixel clks) */ 185 hbp = sc->sc_mode.htotal - sc->sc_mode.hsync_end; 186 WR1(sc, HDMI_FC_HSYNCINDELAY1, hbp >> 8); 187 WR1(sc, HDMI_FC_HSYNCINDELAY0, hbp); 188 189 /* Set up VSYNC active edge delay (in pixel clks) */ 190 vbp = sc->sc_mode.vtotal - sc->sc_mode.vsync_end; 191 WR1(sc, HDMI_FC_VSYNCINDELAY, vbp); 192 193 hsync_len = (sc->sc_mode.hsync_end - sc->sc_mode.hsync_start); 194 /* Set up HSYNC active pulse width (in pixel clks) */ 195 WR1(sc, HDMI_FC_HSYNCINWIDTH1, hsync_len >> 8); 196 WR1(sc, HDMI_FC_HSYNCINWIDTH0, hsync_len); 197 198 /* Set up VSYNC active edge delay (in pixel clks) */ 199 WR1(sc, HDMI_FC_VSYNCINWIDTH, (sc->sc_mode.vsync_end - sc->sc_mode.vsync_start)); 200 } 201 202 static void 203 imx_hdmi_phy_enable_power(struct imx_hdmi_softc *sc, uint8_t enable) 204 { 205 uint8_t reg; 206 207 reg = RD1(sc, HDMI_PHY_CONF0); 208 reg &= ~HDMI_PHY_CONF0_PDZ_MASK; 209 reg |= (enable << HDMI_PHY_CONF0_PDZ_OFFSET); 210 WR1(sc, HDMI_PHY_CONF0, reg); 211 } 212 213 static void 214 imx_hdmi_phy_enable_tmds(struct imx_hdmi_softc *sc, uint8_t enable) 215 { 216 uint8_t reg; 217 218 reg = RD1(sc, HDMI_PHY_CONF0); 219 reg &= ~HDMI_PHY_CONF0_ENTMDS_MASK; 220 reg |= (enable << HDMI_PHY_CONF0_ENTMDS_OFFSET); 221 WR1(sc, HDMI_PHY_CONF0, reg); 222 } 223 224 static void 225 imx_hdmi_phy_gen2_pddq(struct imx_hdmi_softc *sc, uint8_t enable) 226 { 227 uint8_t reg; 228 229 reg = RD1(sc, HDMI_PHY_CONF0); 230 reg &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK; 231 reg |= (enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET); 232 WR1(sc, HDMI_PHY_CONF0, reg); 233 } 234 235 static void 236 imx_hdmi_phy_gen2_txpwron(struct imx_hdmi_softc *sc, uint8_t enable) 237 { 238 uint8_t reg; 239 240 reg = RD1(sc, HDMI_PHY_CONF0); 241 reg &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK; 242 reg |= (enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET); 243 WR1(sc, HDMI_PHY_CONF0, reg); 244 } 245 246 static void 247 imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi_softc *sc, uint8_t enable) 248 { 249 uint8_t reg; 250 251 reg = RD1(sc, HDMI_PHY_CONF0); 252 reg &= ~HDMI_PHY_CONF0_SELDATAENPOL_MASK; 253 reg |= (enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET); 254 WR1(sc, HDMI_PHY_CONF0, reg); 255 } 256 257 static void 258 imx_hdmi_phy_sel_interface_control(struct imx_hdmi_softc *sc, uint8_t enable) 259 { 260 uint8_t reg; 261 262 reg = RD1(sc, HDMI_PHY_CONF0); 263 reg &= ~HDMI_PHY_CONF0_SELDIPIF_MASK; 264 reg |= (enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET); 265 WR1(sc, HDMI_PHY_CONF0, reg); 266 } 267 268 static inline void 269 imx_hdmi_phy_test_clear(struct imx_hdmi_softc *sc, unsigned char bit) 270 { 271 uint8_t val; 272 273 val = RD1(sc, HDMI_PHY_TST0); 274 val &= ~HDMI_PHY_TST0_TSTCLR_MASK; 275 val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) & 276 HDMI_PHY_TST0_TSTCLR_MASK; 277 WR1(sc, HDMI_PHY_TST0, val); 278 } 279 280 static void 281 imx_hdmi_clear_overflow(struct imx_hdmi_softc *sc) 282 { 283 int count; 284 uint8_t val; 285 286 /* TMDS software reset */ 287 WR1(sc, HDMI_MC_SWRSTZ, (uint8_t)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ); 288 289 val = RD1(sc, HDMI_FC_INVIDCONF); 290 291 for (count = 0 ; count < 5 ; count++) 292 WR1(sc, HDMI_FC_INVIDCONF, val); 293 } 294 295 static int 296 imx_hdmi_phy_configure(struct imx_hdmi_softc *sc) 297 { 298 uint8_t val; 299 uint8_t msec; 300 301 WR1(sc, HDMI_MC_FLOWCTRL, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS); 302 303 /* gen2 tx power off */ 304 imx_hdmi_phy_gen2_txpwron(sc, 0); 305 306 /* gen2 pddq */ 307 imx_hdmi_phy_gen2_pddq(sc, 1); 308 309 /* PHY reset */ 310 WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_DEASSERT); 311 WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_ASSERT); 312 313 WR1(sc, HDMI_MC_HEACPHY_RST, HDMI_MC_HEACPHY_RST_ASSERT); 314 315 imx_hdmi_phy_test_clear(sc, 1); 316 WR1(sc, HDMI_PHY_I2CM_SLAVE_ADDR, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2); 317 imx_hdmi_phy_test_clear(sc, 0); 318 319 /* 320 * Following initialization are for 8bit per color case 321 */ 322 323 /* 324 * PLL/MPLL config, see section 24.7.22 in TRM 325 * config, see section 24.7.22 326 */ 327 if (sc->sc_mode.dot_clock*1000 <= 45250000) { 328 imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_45_25, HDMI_PHY_I2C_CPCE_CTRL); 329 imx_hdmi_phy_i2c_write(sc, GMPCTRL_45_25, HDMI_PHY_I2C_GMPCTRL); 330 } else if (sc->sc_mode.dot_clock*1000 <= 92500000) { 331 imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_92_50, HDMI_PHY_I2C_CPCE_CTRL); 332 imx_hdmi_phy_i2c_write(sc, GMPCTRL_92_50, HDMI_PHY_I2C_GMPCTRL); 333 } else if (sc->sc_mode.dot_clock*1000 <= 185000000) { 334 imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_185, HDMI_PHY_I2C_CPCE_CTRL); 335 imx_hdmi_phy_i2c_write(sc, GMPCTRL_185, HDMI_PHY_I2C_GMPCTRL); 336 } else { 337 imx_hdmi_phy_i2c_write(sc, CPCE_CTRL_370, HDMI_PHY_I2C_CPCE_CTRL); 338 imx_hdmi_phy_i2c_write(sc, GMPCTRL_370, HDMI_PHY_I2C_GMPCTRL); 339 } 340 341 /* 342 * Values described in TRM section 34.9.2 PLL/MPLL Generic 343 * Configuration Settings. Table 34-23. 344 */ 345 if (sc->sc_mode.dot_clock*1000 <= 54000000) { 346 imx_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL); 347 } else if (sc->sc_mode.dot_clock*1000 <= 58400000) { 348 imx_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL); 349 } else if (sc->sc_mode.dot_clock*1000 <= 72000000) { 350 imx_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL); 351 } else if (sc->sc_mode.dot_clock*1000 <= 74250000) { 352 imx_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL); 353 } else if (sc->sc_mode.dot_clock*1000 <= 118800000) { 354 imx_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL); 355 } else if (sc->sc_mode.dot_clock*1000 <= 216000000) { 356 imx_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL); 357 } else { 358 panic("Unsupported mode\n"); 359 } 360 361 imx_hdmi_phy_i2c_write(sc, 0x0000, HDMI_PHY_I2C_PLLPHBYCTRL); 362 imx_hdmi_phy_i2c_write(sc, MSM_CTRL_FB_CLK, HDMI_PHY_I2C_MSM_CTRL); 363 /* RESISTANCE TERM 133 Ohm */ 364 imx_hdmi_phy_i2c_write(sc, TXTERM_133, HDMI_PHY_I2C_TXTERM); 365 366 /* REMOVE CLK TERM */ 367 imx_hdmi_phy_i2c_write(sc, CKCALCTRL_OVERRIDE, HDMI_PHY_I2C_CKCALCTRL); 368 369 if (sc->sc_mode.dot_clock*1000 > 148500000) { 370 imx_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON | 371 CKSYMTXCTRL_TX_TRBON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL); 372 imx_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(9) | VLEVCTRL_CK_LVL(9), 373 HDMI_PHY_I2C_VLEVCTRL); 374 } else { 375 imx_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON | 376 CKSYMTXCTRL_TX_TRAON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL); 377 imx_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(13) | VLEVCTRL_CK_LVL(13), 378 HDMI_PHY_I2C_VLEVCTRL); 379 } 380 381 imx_hdmi_phy_enable_power(sc, 1); 382 383 /* toggle TMDS enable */ 384 imx_hdmi_phy_enable_tmds(sc, 0); 385 imx_hdmi_phy_enable_tmds(sc, 1); 386 387 /* gen2 tx power on */ 388 imx_hdmi_phy_gen2_txpwron(sc, 1); 389 imx_hdmi_phy_gen2_pddq(sc, 0); 390 391 /*Wait for PHY PLL lock */ 392 msec = 4; 393 val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; 394 while (val == 0) { 395 DELAY(1000); 396 if (msec-- == 0) { 397 device_printf(sc->sc_dev, "PHY PLL not locked\n"); 398 return (-1); 399 } 400 val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; 401 } 402 403 return true; 404 } 405 406 static void 407 imx_hdmi_phy_init(struct imx_hdmi_softc *sc) 408 { 409 int i; 410 411 /* HDMI Phy spec says to do the phy initialization sequence twice */ 412 for (i = 0 ; i < 2 ; i++) { 413 imx_hdmi_phy_sel_data_en_pol(sc, 1); 414 imx_hdmi_phy_sel_interface_control(sc, 0); 415 imx_hdmi_phy_enable_tmds(sc, 0); 416 imx_hdmi_phy_enable_power(sc, 0); 417 418 /* Enable CSC */ 419 imx_hdmi_phy_configure(sc); 420 } 421 } 422 423 static void 424 imx_hdmi_enable_video_path(struct imx_hdmi_softc *sc) 425 { 426 uint8_t clkdis; 427 428 /* 429 * Control period timing 430 * Values are minimal according to HDMI spec 1.4a 431 */ 432 WR1(sc, HDMI_FC_CTRLDUR, 12); 433 WR1(sc, HDMI_FC_EXCTRLDUR, 32); 434 WR1(sc, HDMI_FC_EXCTRLSPAC, 1); 435 436 /* 437 * Bits to fill data lines not used to transmit preamble 438 * for channels 0, 1, and 2 respectively 439 */ 440 WR1(sc, HDMI_FC_CH0PREAM, 0x0B); 441 WR1(sc, HDMI_FC_CH1PREAM, 0x16); 442 WR1(sc, HDMI_FC_CH2PREAM, 0x21); 443 444 /* Save CEC clock */ 445 clkdis = RD1(sc, HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE; 446 clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; 447 448 /* Enable pixel clock and tmds data path */ 449 clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; 450 WR1(sc, HDMI_MC_CLKDIS, clkdis); 451 452 clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; 453 WR1(sc, HDMI_MC_CLKDIS, clkdis); 454 } 455 456 static void 457 imx_hdmi_video_packetize(struct imx_hdmi_softc *sc) 458 { 459 unsigned int color_depth = 0; 460 unsigned int remap_size = HDMI_VP_REMAP_YCC422_16BIT; 461 unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; 462 uint8_t val; 463 464 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; 465 color_depth = 0; 466 467 /* set the packetizer registers */ 468 val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & 469 HDMI_VP_PR_CD_COLOR_DEPTH_MASK); 470 WR1(sc, HDMI_VP_PR_CD, val); 471 472 val = RD1(sc, HDMI_VP_STUFF); 473 val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK; 474 val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE; 475 WR1(sc, HDMI_VP_STUFF, val); 476 477 val = RD1(sc, HDMI_VP_CONF); 478 val &= ~(HDMI_VP_CONF_PR_EN_MASK | 479 HDMI_VP_CONF_BYPASS_SELECT_MASK); 480 val |= HDMI_VP_CONF_PR_EN_DISABLE | 481 HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; 482 WR1(sc, HDMI_VP_CONF, val); 483 484 val = RD1(sc, HDMI_VP_STUFF); 485 val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK; 486 val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET; 487 WR1(sc, HDMI_VP_STUFF, val); 488 489 WR1(sc, HDMI_VP_REMAP, remap_size); 490 491 if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { 492 val = RD1(sc, HDMI_VP_CONF); 493 val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | 494 HDMI_VP_CONF_PP_EN_ENMASK | 495 HDMI_VP_CONF_YCC422_EN_MASK); 496 val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | 497 HDMI_VP_CONF_PP_EN_ENABLE | 498 HDMI_VP_CONF_YCC422_EN_DISABLE; 499 WR1(sc, HDMI_VP_CONF, val); 500 } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { 501 val = RD1(sc, HDMI_VP_CONF); 502 val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | 503 HDMI_VP_CONF_PP_EN_ENMASK | 504 HDMI_VP_CONF_YCC422_EN_MASK); 505 val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | 506 HDMI_VP_CONF_PP_EN_DISABLE | 507 HDMI_VP_CONF_YCC422_EN_ENABLE; 508 WR1(sc, HDMI_VP_CONF, val); 509 } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { 510 val = RD1(sc, HDMI_VP_CONF); 511 val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | 512 HDMI_VP_CONF_PP_EN_ENMASK | 513 HDMI_VP_CONF_YCC422_EN_MASK); 514 val |= HDMI_VP_CONF_BYPASS_EN_ENABLE | 515 HDMI_VP_CONF_PP_EN_DISABLE | 516 HDMI_VP_CONF_YCC422_EN_DISABLE; 517 WR1(sc, HDMI_VP_CONF, val); 518 } else { 519 return; 520 } 521 522 val = RD1(sc, HDMI_VP_STUFF); 523 val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK | 524 HDMI_VP_STUFF_YCC422_STUFFING_MASK); 525 val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | 526 HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE; 527 WR1(sc, HDMI_VP_STUFF, val); 528 529 val = RD1(sc, HDMI_VP_CONF); 530 val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK; 531 val |= output_select; 532 WR1(sc, HDMI_VP_CONF, val); 533 } 534 535 static void 536 imx_hdmi_video_sample(struct imx_hdmi_softc *sc) 537 { 538 int color_format; 539 uint8_t val; 540 541 color_format = 0x01; 542 val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | 543 ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) & 544 HDMI_TX_INVID0_VIDEO_MAPPING_MASK); 545 WR1(sc, HDMI_TX_INVID0, val); 546 547 /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */ 548 val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE | 549 HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE | 550 HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE; 551 WR1(sc, HDMI_TX_INSTUFFING, val); 552 WR1(sc, HDMI_TX_GYDATA0, 0x0); 553 WR1(sc, HDMI_TX_GYDATA1, 0x0); 554 WR1(sc, HDMI_TX_RCRDATA0, 0x0); 555 WR1(sc, HDMI_TX_RCRDATA1, 0x0); 556 WR1(sc, HDMI_TX_BCBDATA0, 0x0); 557 WR1(sc, HDMI_TX_BCBDATA1, 0x0); 558 } 559 560 static int 561 imx_hdmi_set_mode(struct imx_hdmi_softc *sc) 562 { 563 564 imx_hdmi_disable_overflow_interrupts(sc); 565 imx_hdmi_av_composer(sc); 566 imx_hdmi_phy_init(sc); 567 imx_hdmi_enable_video_path(sc); 568 /* TODO: AVI infoframes */ 569 imx_hdmi_video_packetize(sc); 570 /* TODO: imx_hdmi_video_csc(sc); */ 571 imx_hdmi_video_sample(sc); 572 imx_hdmi_clear_overflow(sc); 573 574 return (0); 575 } 576 577 static int 578 hdmi_edid_read(struct imx_hdmi_softc *sc, uint8_t **edid, uint32_t *edid_len) 579 { 580 device_t i2c_dev; 581 int result; 582 uint8_t addr = 0; 583 struct iic_msg msg[] = { 584 { 0, IIC_M_WR, 1, &addr }, 585 { 0, IIC_M_RD, EDID_LENGTH, NULL} 586 }; 587 588 *edid = NULL; 589 *edid_len = 0; 590 591 if (sc->sc_i2c_xref == 0) 592 return (ENXIO); 593 594 i2c_dev = OF_device_from_xref(sc->sc_i2c_xref); 595 if (!i2c_dev) { 596 device_printf(sc->sc_dev, 597 "no actual device for \"ddc-i2c-bus\" property (handle=%x)\n", sc->sc_i2c_xref); 598 return (ENXIO); 599 } 600 601 device_printf(sc->sc_dev, "reading EDID from %s, addr %02x\n", 602 device_get_nameunit(i2c_dev), I2C_DDC_ADDR/2); 603 604 msg[0].slave = I2C_DDC_ADDR; 605 msg[1].slave = I2C_DDC_ADDR; 606 msg[1].buf = sc->sc_edid; 607 608 result = iicbus_request_bus(i2c_dev, sc->sc_dev, IIC_INTRWAIT); 609 610 if (result) { 611 device_printf(sc->sc_dev, "failed to request i2c bus: %d\n", result); 612 return (result); 613 } 614 615 result = iicbus_transfer(i2c_dev, msg, 2); 616 iicbus_release_bus(i2c_dev, sc->sc_dev); 617 618 if (result) { 619 device_printf(sc->sc_dev, "i2c transfer failed: %d\n", result); 620 return (result); 621 } else { 622 *edid_len = sc->sc_edid_len; 623 *edid = sc->sc_edid; 624 } 625 626 return (result); 627 } 628 629 static void 630 imx_hdmi_detect_cable(void *arg) 631 { 632 struct imx_hdmi_softc *sc; 633 634 sc = arg; 635 EVENTHANDLER_INVOKE(hdmi_event, sc->sc_dev, HDMI_EVENT_CONNECTED); 636 /* Finished with the interrupt hook */ 637 config_intrhook_disestablish(&sc->sc_mode_hook); 638 } 639 640 static int 641 imx_hdmi_detach(device_t dev) 642 { 643 struct imx_hdmi_softc *sc; 644 645 sc = device_get_softc(dev); 646 647 if (sc->sc_mem_res != NULL) 648 bus_release_resource(dev, SYS_RES_MEMORY, 649 sc->sc_mem_rid, sc->sc_mem_res); 650 651 return (0); 652 } 653 654 static int 655 imx_hdmi_attach(device_t dev) 656 { 657 struct imx_hdmi_softc *sc; 658 int err; 659 uint32_t gpr3; 660 phandle_t node, i2c_xref; 661 662 sc = device_get_softc(dev); 663 sc->sc_dev = dev; 664 err = 0; 665 666 /* Allocate memory resources. */ 667 sc->sc_mem_rid = 0; 668 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mem_rid, 669 RF_ACTIVE); 670 if (sc->sc_mem_res == NULL) { 671 device_printf(dev, "Cannot allocate memory resources\n"); 672 err = ENXIO; 673 goto out; 674 } 675 676 sc->sc_mode_hook.ich_func = imx_hdmi_detect_cable; 677 sc->sc_mode_hook.ich_arg = sc; 678 679 if (config_intrhook_establish(&sc->sc_mode_hook) != 0) { 680 err = ENOMEM; 681 goto out; 682 } 683 684 node = ofw_bus_get_node(dev); 685 if (OF_getencprop(node, "ddc-i2c-bus", &i2c_xref, sizeof(i2c_xref)) == -1) 686 sc->sc_i2c_xref = 0; 687 else 688 sc->sc_i2c_xref = i2c_xref; 689 690 sc->sc_edid = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO); 691 sc->sc_edid_len = EDID_LENGTH; 692 693 imx_ccm_hdmi_enable(); 694 695 device_printf(sc->sc_dev, "HDMI controller %02x:%02x:%02x:%02x\n", 696 RD1(sc, HDMI_DESIGN_ID), RD1(sc, HDMI_REVISION_ID), 697 RD1(sc, HDMI_PRODUCT_ID0), RD1(sc, HDMI_PRODUCT_ID1)); 698 699 700 gpr3 = imx_iomux_gpr_get(IOMUXC_GPR3); 701 gpr3 &= ~(IOMUXC_GPR3_HDMI_MASK); 702 gpr3 |= IOMUXC_GPR3_HDMI_IPU1_DI0; 703 imx_iomux_gpr_set(IOMUXC_GPR3, gpr3); 704 705 WR1(sc, HDMI_PHY_POL0, HDMI_PHY_HPD); 706 WR1(sc, HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD); 707 708 out: 709 710 if (err != 0) 711 imx_hdmi_detach(dev); 712 713 return (err); 714 } 715 716 static int 717 imx_hdmi_probe(device_t dev) 718 { 719 720 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 721 return (ENXIO); 722 723 device_set_desc(dev, "Freescale i.MX6 HDMI core"); 724 725 return (BUS_PROBE_DEFAULT); 726 } 727 728 static int 729 imx_hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len) 730 { 731 732 return (hdmi_edid_read(device_get_softc(dev), edid, edid_len)); 733 } 734 735 static int 736 imx_hdmi_set_videomode(device_t dev, const struct videomode *mode) 737 { 738 struct imx_hdmi_softc *sc; 739 740 sc = device_get_softc(dev); 741 memcpy(&sc->sc_mode, mode, sizeof(*mode)); 742 imx_hdmi_set_mode(sc); 743 744 return (0); 745 } 746 747 static device_method_t imx_hdmi_methods[] = { 748 /* Device interface */ 749 DEVMETHOD(device_probe, imx_hdmi_probe), 750 DEVMETHOD(device_attach, imx_hdmi_attach), 751 DEVMETHOD(device_detach, imx_hdmi_detach), 752 753 /* HDMI methods */ 754 DEVMETHOD(hdmi_get_edid, imx_hdmi_get_edid), 755 DEVMETHOD(hdmi_set_videomode, imx_hdmi_set_videomode), 756 757 DEVMETHOD_END 758 }; 759 760 static driver_t imx_hdmi_driver = { 761 "hdmi", 762 imx_hdmi_methods, 763 sizeof(struct imx_hdmi_softc) 764 }; 765 766 static devclass_t imx_hdmi_devclass; 767 768 DRIVER_MODULE(hdmi, simplebus, imx_hdmi_driver, imx_hdmi_devclass, 0, 0); 769