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/malloc.h> 39 #include <sys/bus.h> 40 #include <sys/rman.h> 41 42 #include <machine/bus.h> 43 44 #include <dev/videomode/videomode.h> 45 #include <dev/videomode/edidvar.h> 46 47 #include <dev/iicbus/iicbus.h> 48 #include <dev/iicbus/iiconf.h> 49 50 #include <dev/hdmi/dwc_hdmi.h> 51 #include <dev/hdmi/dwc_hdmireg.h> 52 53 #include "hdmi_if.h" 54 55 #define I2C_DDC_ADDR (0x50 << 1) 56 #define EDID_LENGTH 0x80 57 58 static void 59 dwc_hdmi_phy_wait_i2c_done(struct dwc_hdmi_softc *sc, int msec) 60 { 61 uint8_t val; 62 63 val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) & 64 (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR); 65 while (val == 0) { 66 pause("HDMI_PHY", hz/100); 67 msec -= 10; 68 if (msec <= 0) 69 return; 70 val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) & 71 (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR); 72 } 73 } 74 75 static void 76 dwc_hdmi_phy_i2c_write(struct dwc_hdmi_softc *sc, unsigned short data, 77 unsigned char addr) 78 { 79 80 /* clear DONE and ERROR flags */ 81 WR1(sc, HDMI_IH_I2CMPHY_STAT0, 82 HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR); 83 WR1(sc, HDMI_PHY_I2CM_ADDRESS_ADDR, addr); 84 WR1(sc, HDMI_PHY_I2CM_DATAO_1_ADDR, ((data >> 8) & 0xff)); 85 WR1(sc, HDMI_PHY_I2CM_DATAO_0_ADDR, ((data >> 0) & 0xff)); 86 WR1(sc, HDMI_PHY_I2CM_OPERATION_ADDR, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE); 87 dwc_hdmi_phy_wait_i2c_done(sc, 1000); 88 } 89 90 static void 91 dwc_hdmi_disable_overflow_interrupts(struct dwc_hdmi_softc *sc) 92 { 93 WR1(sc, HDMI_IH_MUTE_FC_STAT2, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK); 94 WR1(sc, HDMI_FC_MASK2, 95 HDMI_FC_MASK2_LOW_PRI | HDMI_FC_MASK2_HIGH_PRI); 96 } 97 98 static void 99 dwc_hdmi_av_composer(struct dwc_hdmi_softc *sc) 100 { 101 uint8_t inv_val; 102 int is_dvi; 103 int hblank, vblank, hsync_len, hfp, vfp; 104 105 /* Set up HDMI_FC_INVIDCONF */ 106 inv_val = ((sc->sc_mode.flags & VID_PVSYNC) ? 107 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH : 108 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW); 109 110 inv_val |= ((sc->sc_mode.flags & VID_PHSYNC) ? 111 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH : 112 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW); 113 114 inv_val |= HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH; 115 116 inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ? 117 HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH : 118 HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW); 119 120 inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ? 121 HDMI_FC_INVIDCONF_IN_I_P_INTERLACED : 122 HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE); 123 124 /* TODO: implement HDMI part */ 125 is_dvi = 1; 126 inv_val |= (is_dvi ? 127 HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE : 128 HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE); 129 130 WR1(sc, HDMI_FC_INVIDCONF, inv_val); 131 132 /* Set up horizontal active pixel region width */ 133 WR1(sc, HDMI_FC_INHACTV1, sc->sc_mode.hdisplay >> 8); 134 WR1(sc, HDMI_FC_INHACTV0, sc->sc_mode.hdisplay); 135 136 /* Set up vertical blanking pixel region width */ 137 WR1(sc, HDMI_FC_INVACTV1, sc->sc_mode.vdisplay >> 8); 138 WR1(sc, HDMI_FC_INVACTV0, sc->sc_mode.vdisplay); 139 140 /* Set up horizontal blanking pixel region width */ 141 hblank = sc->sc_mode.htotal - sc->sc_mode.hdisplay; 142 WR1(sc, HDMI_FC_INHBLANK1, hblank >> 8); 143 WR1(sc, HDMI_FC_INHBLANK0, hblank); 144 145 /* Set up vertical blanking pixel region width */ 146 vblank = sc->sc_mode.vtotal - sc->sc_mode.vdisplay; 147 WR1(sc, HDMI_FC_INVBLANK, vblank); 148 149 /* Set up HSYNC active edge delay width (in pixel clks) */ 150 hfp = sc->sc_mode.hsync_start - sc->sc_mode.hdisplay; 151 WR1(sc, HDMI_FC_HSYNCINDELAY1, hfp >> 8); 152 WR1(sc, HDMI_FC_HSYNCINDELAY0, hfp); 153 154 /* Set up VSYNC active edge delay (in pixel clks) */ 155 vfp = sc->sc_mode.vsync_start - sc->sc_mode.vdisplay; 156 WR1(sc, HDMI_FC_VSYNCINDELAY, vfp); 157 158 hsync_len = (sc->sc_mode.hsync_end - sc->sc_mode.hsync_start); 159 /* Set up HSYNC active pulse width (in pixel clks) */ 160 WR1(sc, HDMI_FC_HSYNCINWIDTH1, hsync_len >> 8); 161 WR1(sc, HDMI_FC_HSYNCINWIDTH0, hsync_len); 162 163 /* Set up VSYNC active edge delay (in pixel clks) */ 164 WR1(sc, HDMI_FC_VSYNCINWIDTH, (sc->sc_mode.vsync_end - sc->sc_mode.vsync_start)); 165 } 166 167 static void 168 dwc_hdmi_phy_enable_power(struct dwc_hdmi_softc *sc, uint8_t enable) 169 { 170 uint8_t reg; 171 172 reg = RD1(sc, HDMI_PHY_CONF0); 173 reg &= ~HDMI_PHY_CONF0_PDZ_MASK; 174 reg |= (enable << HDMI_PHY_CONF0_PDZ_OFFSET); 175 WR1(sc, HDMI_PHY_CONF0, reg); 176 } 177 178 static void 179 dwc_hdmi_phy_enable_tmds(struct dwc_hdmi_softc *sc, uint8_t enable) 180 { 181 uint8_t reg; 182 183 reg = RD1(sc, HDMI_PHY_CONF0); 184 reg &= ~HDMI_PHY_CONF0_ENTMDS_MASK; 185 reg |= (enable << HDMI_PHY_CONF0_ENTMDS_OFFSET); 186 WR1(sc, HDMI_PHY_CONF0, reg); 187 } 188 189 static void 190 dwc_hdmi_phy_gen2_pddq(struct dwc_hdmi_softc *sc, uint8_t enable) 191 { 192 uint8_t reg; 193 194 reg = RD1(sc, HDMI_PHY_CONF0); 195 reg &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK; 196 reg |= (enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET); 197 WR1(sc, HDMI_PHY_CONF0, reg); 198 } 199 200 static void 201 dwc_hdmi_phy_gen2_txpwron(struct dwc_hdmi_softc *sc, uint8_t enable) 202 { 203 uint8_t reg; 204 205 reg = RD1(sc, HDMI_PHY_CONF0); 206 reg &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK; 207 reg |= (enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET); 208 WR1(sc, HDMI_PHY_CONF0, reg); 209 } 210 211 static void 212 dwc_hdmi_phy_sel_data_en_pol(struct dwc_hdmi_softc *sc, uint8_t enable) 213 { 214 uint8_t reg; 215 216 reg = RD1(sc, HDMI_PHY_CONF0); 217 reg &= ~HDMI_PHY_CONF0_SELDATAENPOL_MASK; 218 reg |= (enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET); 219 WR1(sc, HDMI_PHY_CONF0, reg); 220 } 221 222 static void 223 dwc_hdmi_phy_sel_interface_control(struct dwc_hdmi_softc *sc, uint8_t enable) 224 { 225 uint8_t reg; 226 227 reg = RD1(sc, HDMI_PHY_CONF0); 228 reg &= ~HDMI_PHY_CONF0_SELDIPIF_MASK; 229 reg |= (enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET); 230 WR1(sc, HDMI_PHY_CONF0, reg); 231 } 232 233 static inline void 234 dwc_hdmi_phy_test_clear(struct dwc_hdmi_softc *sc, unsigned char bit) 235 { 236 uint8_t val; 237 238 val = RD1(sc, HDMI_PHY_TST0); 239 val &= ~HDMI_PHY_TST0_TSTCLR_MASK; 240 val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) & 241 HDMI_PHY_TST0_TSTCLR_MASK; 242 WR1(sc, HDMI_PHY_TST0, val); 243 } 244 245 static void 246 dwc_hdmi_clear_overflow(struct dwc_hdmi_softc *sc) 247 { 248 int count; 249 uint8_t val; 250 251 /* TMDS software reset */ 252 WR1(sc, HDMI_MC_SWRSTZ, (uint8_t)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ); 253 254 val = RD1(sc, HDMI_FC_INVIDCONF); 255 256 for (count = 0 ; count < 4 ; count++) 257 WR1(sc, HDMI_FC_INVIDCONF, val); 258 } 259 260 static int 261 dwc_hdmi_phy_configure(struct dwc_hdmi_softc *sc) 262 { 263 uint8_t val; 264 uint8_t msec; 265 266 WR1(sc, HDMI_MC_FLOWCTRL, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS); 267 268 /* gen2 tx power off */ 269 dwc_hdmi_phy_gen2_txpwron(sc, 0); 270 271 /* gen2 pddq */ 272 dwc_hdmi_phy_gen2_pddq(sc, 1); 273 274 /* PHY reset */ 275 WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_DEASSERT); 276 WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_ASSERT); 277 278 WR1(sc, HDMI_MC_HEACPHY_RST, HDMI_MC_HEACPHY_RST_ASSERT); 279 280 dwc_hdmi_phy_test_clear(sc, 1); 281 WR1(sc, HDMI_PHY_I2CM_SLAVE_ADDR, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2); 282 dwc_hdmi_phy_test_clear(sc, 0); 283 284 /* 285 * Following initialization are for 8bit per color case 286 */ 287 288 /* 289 * PLL/MPLL config, see section 24.7.22 in TRM 290 * config, see section 24.7.22 291 */ 292 if (sc->sc_mode.dot_clock*1000 <= 45250000) { 293 dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_45_25, HDMI_PHY_I2C_CPCE_CTRL); 294 dwc_hdmi_phy_i2c_write(sc, GMPCTRL_45_25, HDMI_PHY_I2C_GMPCTRL); 295 } else if (sc->sc_mode.dot_clock*1000 <= 92500000) { 296 dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_92_50, HDMI_PHY_I2C_CPCE_CTRL); 297 dwc_hdmi_phy_i2c_write(sc, GMPCTRL_92_50, HDMI_PHY_I2C_GMPCTRL); 298 } else if (sc->sc_mode.dot_clock*1000 <= 185000000) { 299 dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_185, HDMI_PHY_I2C_CPCE_CTRL); 300 dwc_hdmi_phy_i2c_write(sc, GMPCTRL_185, HDMI_PHY_I2C_GMPCTRL); 301 } else { 302 dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_370, HDMI_PHY_I2C_CPCE_CTRL); 303 dwc_hdmi_phy_i2c_write(sc, GMPCTRL_370, HDMI_PHY_I2C_GMPCTRL); 304 } 305 306 /* 307 * Values described in TRM section 34.9.2 PLL/MPLL Generic 308 * Configuration Settings. Table 34-23. 309 */ 310 if (sc->sc_mode.dot_clock*1000 <= 54000000) { 311 dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL); 312 } else if (sc->sc_mode.dot_clock*1000 <= 58400000) { 313 dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL); 314 } else if (sc->sc_mode.dot_clock*1000 <= 72000000) { 315 dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL); 316 } else if (sc->sc_mode.dot_clock*1000 <= 74250000) { 317 dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL); 318 } else if (sc->sc_mode.dot_clock*1000 <= 118800000) { 319 dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL); 320 } else if (sc->sc_mode.dot_clock*1000 <= 216000000) { 321 dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL); 322 } else { 323 panic("Unsupported mode\n"); 324 } 325 326 dwc_hdmi_phy_i2c_write(sc, 0x0000, HDMI_PHY_I2C_PLLPHBYCTRL); 327 dwc_hdmi_phy_i2c_write(sc, MSM_CTRL_FB_CLK, HDMI_PHY_I2C_MSM_CTRL); 328 /* RESISTANCE TERM 133 Ohm */ 329 dwc_hdmi_phy_i2c_write(sc, TXTERM_133, HDMI_PHY_I2C_TXTERM); 330 331 /* REMOVE CLK TERM */ 332 dwc_hdmi_phy_i2c_write(sc, CKCALCTRL_OVERRIDE, HDMI_PHY_I2C_CKCALCTRL); 333 334 if (sc->sc_mode.dot_clock*1000 > 148500000) { 335 dwc_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON | 336 CKSYMTXCTRL_TX_TRBON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL); 337 dwc_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(9) | VLEVCTRL_CK_LVL(9), 338 HDMI_PHY_I2C_VLEVCTRL); 339 } else { 340 dwc_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON | 341 CKSYMTXCTRL_TX_TRAON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL); 342 dwc_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(13) | VLEVCTRL_CK_LVL(13), 343 HDMI_PHY_I2C_VLEVCTRL); 344 } 345 346 dwc_hdmi_phy_enable_power(sc, 1); 347 348 /* toggle TMDS enable */ 349 dwc_hdmi_phy_enable_tmds(sc, 0); 350 dwc_hdmi_phy_enable_tmds(sc, 1); 351 352 /* gen2 tx power on */ 353 dwc_hdmi_phy_gen2_txpwron(sc, 1); 354 dwc_hdmi_phy_gen2_pddq(sc, 0); 355 356 /*Wait for PHY PLL lock */ 357 msec = 4; 358 val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; 359 while (val == 0) { 360 DELAY(1000); 361 if (msec-- == 0) { 362 device_printf(sc->sc_dev, "PHY PLL not locked\n"); 363 return (-1); 364 } 365 val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; 366 } 367 368 return true; 369 } 370 371 static void 372 dwc_hdmi_phy_init(struct dwc_hdmi_softc *sc) 373 { 374 int i; 375 376 /* HDMI Phy spec says to do the phy initialization sequence twice */ 377 for (i = 0 ; i < 2 ; i++) { 378 dwc_hdmi_phy_sel_data_en_pol(sc, 1); 379 dwc_hdmi_phy_sel_interface_control(sc, 0); 380 dwc_hdmi_phy_enable_tmds(sc, 0); 381 dwc_hdmi_phy_enable_power(sc, 0); 382 383 /* Enable CSC */ 384 dwc_hdmi_phy_configure(sc); 385 } 386 } 387 388 static void 389 dwc_hdmi_enable_video_path(struct dwc_hdmi_softc *sc) 390 { 391 uint8_t clkdis; 392 393 /* 394 * Control period timing 395 * Values are minimal according to HDMI spec 1.4a 396 */ 397 WR1(sc, HDMI_FC_CTRLDUR, 12); 398 WR1(sc, HDMI_FC_EXCTRLDUR, 32); 399 WR1(sc, HDMI_FC_EXCTRLSPAC, 1); 400 401 /* 402 * Bits to fill data lines not used to transmit preamble 403 * for channels 0, 1, and 2 respectively 404 */ 405 WR1(sc, HDMI_FC_CH0PREAM, 0x0B); 406 WR1(sc, HDMI_FC_CH1PREAM, 0x16); 407 WR1(sc, HDMI_FC_CH2PREAM, 0x21); 408 409 /* Save CEC clock */ 410 clkdis = RD1(sc, HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE; 411 clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; 412 413 /* Enable pixel clock and tmds data path */ 414 clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; 415 WR1(sc, HDMI_MC_CLKDIS, clkdis); 416 417 clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; 418 WR1(sc, HDMI_MC_CLKDIS, clkdis); 419 } 420 421 static void 422 dwc_hdmi_video_packetize(struct dwc_hdmi_softc *sc) 423 { 424 unsigned int color_depth = 0; 425 unsigned int remap_size = HDMI_VP_REMAP_YCC422_16BIT; 426 unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; 427 uint8_t val; 428 429 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; 430 color_depth = 4; 431 432 /* set the packetizer registers */ 433 val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & 434 HDMI_VP_PR_CD_COLOR_DEPTH_MASK); 435 WR1(sc, HDMI_VP_PR_CD, val); 436 437 val = RD1(sc, HDMI_VP_STUFF); 438 val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK; 439 val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE; 440 WR1(sc, HDMI_VP_STUFF, val); 441 442 val = RD1(sc, HDMI_VP_CONF); 443 val &= ~(HDMI_VP_CONF_PR_EN_MASK | 444 HDMI_VP_CONF_BYPASS_SELECT_MASK); 445 val |= HDMI_VP_CONF_PR_EN_DISABLE | 446 HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; 447 WR1(sc, HDMI_VP_CONF, val); 448 449 val = RD1(sc, HDMI_VP_STUFF); 450 val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK; 451 val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET; 452 WR1(sc, HDMI_VP_STUFF, val); 453 454 WR1(sc, HDMI_VP_REMAP, remap_size); 455 456 if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { 457 val = RD1(sc, HDMI_VP_CONF); 458 val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | 459 HDMI_VP_CONF_PP_EN_ENMASK | 460 HDMI_VP_CONF_YCC422_EN_MASK); 461 val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | 462 HDMI_VP_CONF_PP_EN_ENABLE | 463 HDMI_VP_CONF_YCC422_EN_DISABLE; 464 WR1(sc, HDMI_VP_CONF, val); 465 } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { 466 val = RD1(sc, HDMI_VP_CONF); 467 val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | 468 HDMI_VP_CONF_PP_EN_ENMASK | 469 HDMI_VP_CONF_YCC422_EN_MASK); 470 val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | 471 HDMI_VP_CONF_PP_EN_DISABLE | 472 HDMI_VP_CONF_YCC422_EN_ENABLE; 473 WR1(sc, HDMI_VP_CONF, val); 474 } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { 475 val = RD1(sc, HDMI_VP_CONF); 476 val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | 477 HDMI_VP_CONF_PP_EN_ENMASK | 478 HDMI_VP_CONF_YCC422_EN_MASK); 479 val |= HDMI_VP_CONF_BYPASS_EN_ENABLE | 480 HDMI_VP_CONF_PP_EN_DISABLE | 481 HDMI_VP_CONF_YCC422_EN_DISABLE; 482 WR1(sc, HDMI_VP_CONF, val); 483 } else { 484 return; 485 } 486 487 val = RD1(sc, HDMI_VP_STUFF); 488 val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK | 489 HDMI_VP_STUFF_YCC422_STUFFING_MASK); 490 val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | 491 HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE; 492 WR1(sc, HDMI_VP_STUFF, val); 493 494 val = RD1(sc, HDMI_VP_CONF); 495 val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK; 496 val |= output_select; 497 WR1(sc, HDMI_VP_CONF, val); 498 } 499 500 static void 501 dwc_hdmi_video_sample(struct dwc_hdmi_softc *sc) 502 { 503 int color_format; 504 uint8_t val; 505 506 color_format = 0x01; 507 val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | 508 ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) & 509 HDMI_TX_INVID0_VIDEO_MAPPING_MASK); 510 WR1(sc, HDMI_TX_INVID0, val); 511 512 /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */ 513 val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE | 514 HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE | 515 HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE; 516 WR1(sc, HDMI_TX_INSTUFFING, val); 517 WR1(sc, HDMI_TX_GYDATA0, 0x0); 518 WR1(sc, HDMI_TX_GYDATA1, 0x0); 519 WR1(sc, HDMI_TX_RCRDATA0, 0x0); 520 WR1(sc, HDMI_TX_RCRDATA1, 0x0); 521 WR1(sc, HDMI_TX_BCBDATA0, 0x0); 522 WR1(sc, HDMI_TX_BCBDATA1, 0x0); 523 } 524 525 static void 526 dwc_hdmi_tx_hdcp_config(struct dwc_hdmi_softc *sc) 527 { 528 uint8_t de, val; 529 530 de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; 531 532 /* Disable RX detect */ 533 val = RD1(sc, HDMI_A_HDCPCFG0); 534 val &= ~HDMI_A_HDCPCFG0_RXDETECT_MASK; 535 val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE; 536 WR1(sc, HDMI_A_HDCPCFG0, val); 537 538 /* Set polarity */ 539 val = RD1(sc, HDMI_A_VIDPOLCFG); 540 val &= ~HDMI_A_VIDPOLCFG_DATAENPOL_MASK; 541 val |= de; 542 WR1(sc, HDMI_A_VIDPOLCFG, val); 543 544 /* Disable encryption */ 545 val = RD1(sc, HDMI_A_HDCPCFG1); 546 val &= ~HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK; 547 val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE; 548 WR1(sc, HDMI_A_HDCPCFG1, val); 549 } 550 551 static int 552 dwc_hdmi_set_mode(struct dwc_hdmi_softc *sc) 553 { 554 555 dwc_hdmi_disable_overflow_interrupts(sc); 556 dwc_hdmi_av_composer(sc); 557 dwc_hdmi_phy_init(sc); 558 dwc_hdmi_enable_video_path(sc); 559 /* TODO: AVI infoframes */ 560 dwc_hdmi_video_packetize(sc); 561 /* TODO: dwc_hdmi_video_csc(sc); */ 562 dwc_hdmi_video_sample(sc); 563 dwc_hdmi_tx_hdcp_config(sc); 564 dwc_hdmi_clear_overflow(sc); 565 566 return (0); 567 } 568 569 static int 570 hdmi_edid_read(struct dwc_hdmi_softc *sc, uint8_t **edid, uint32_t *edid_len) 571 { 572 device_t i2c_dev; 573 int result; 574 uint8_t addr = 0; 575 struct iic_msg msg[] = { 576 { 0, IIC_M_WR, 1, &addr }, 577 { 0, IIC_M_RD, EDID_LENGTH, NULL} 578 }; 579 580 *edid = NULL; 581 *edid_len = 0; 582 i2c_dev = NULL; 583 584 if (sc->sc_get_i2c_dev != NULL) 585 i2c_dev = sc->sc_get_i2c_dev(sc->sc_dev); 586 if (!i2c_dev) { 587 device_printf(sc->sc_dev, "no DDC device found\n"); 588 return (ENXIO); 589 } 590 591 device_printf(sc->sc_dev, "reading EDID from %s, addr %02x\n", 592 device_get_nameunit(i2c_dev), I2C_DDC_ADDR/2); 593 594 msg[0].slave = I2C_DDC_ADDR; 595 msg[1].slave = I2C_DDC_ADDR; 596 msg[1].buf = sc->sc_edid; 597 598 result = iicbus_request_bus(i2c_dev, sc->sc_dev, IIC_INTRWAIT); 599 600 if (result) { 601 device_printf(sc->sc_dev, "failed to request i2c bus: %d\n", result); 602 return (result); 603 } 604 605 result = iicbus_transfer(i2c_dev, msg, 2); 606 iicbus_release_bus(i2c_dev, sc->sc_dev); 607 608 if (result) { 609 device_printf(sc->sc_dev, "i2c transfer failed: %d\n", result); 610 return (result); 611 } else { 612 *edid_len = sc->sc_edid_len; 613 *edid = sc->sc_edid; 614 } 615 616 return (result); 617 } 618 619 static void 620 dwc_hdmi_detect_cable(void *arg) 621 { 622 struct dwc_hdmi_softc *sc; 623 uint32_t stat; 624 625 sc = arg; 626 627 stat = RD1(sc, HDMI_IH_PHY_STAT0); 628 if ((stat & HDMI_IH_PHY_STAT0_HPD) != 0) { 629 EVENTHANDLER_INVOKE(hdmi_event, sc->sc_dev, 630 HDMI_EVENT_CONNECTED); 631 } 632 633 /* Finished with the interrupt hook */ 634 config_intrhook_disestablish(&sc->sc_mode_hook); 635 } 636 637 int 638 dwc_hdmi_init(device_t dev) 639 { 640 struct dwc_hdmi_softc *sc; 641 int err; 642 643 sc = device_get_softc(dev); 644 err = 0; 645 646 sc->sc_edid = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO); 647 sc->sc_edid_len = EDID_LENGTH; 648 649 device_printf(sc->sc_dev, "HDMI controller %02x:%02x:%02x:%02x\n", 650 RD1(sc, HDMI_DESIGN_ID), RD1(sc, HDMI_REVISION_ID), 651 RD1(sc, HDMI_PRODUCT_ID0), RD1(sc, HDMI_PRODUCT_ID1)); 652 653 WR1(sc, HDMI_PHY_POL0, HDMI_PHY_POL0_HPD); 654 WR1(sc, HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD); 655 656 sc->sc_mode_hook.ich_func = dwc_hdmi_detect_cable; 657 sc->sc_mode_hook.ich_arg = sc; 658 if (config_intrhook_establish(&sc->sc_mode_hook) != 0) { 659 err = ENOMEM; 660 goto out; 661 } 662 663 out: 664 665 if (err != 0) { 666 free(sc->sc_edid, M_DEVBUF); 667 sc->sc_edid = NULL; 668 } 669 670 return (err); 671 } 672 673 int 674 dwc_hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len) 675 { 676 677 return (hdmi_edid_read(device_get_softc(dev), edid, edid_len)); 678 } 679 680 int 681 dwc_hdmi_set_videomode(device_t dev, const struct videomode *mode) 682 { 683 struct dwc_hdmi_softc *sc; 684 685 sc = device_get_softc(dev); 686 memcpy(&sc->sc_mode, mode, sizeof(*mode)); 687 688 dwc_hdmi_set_mode(sc); 689 690 return (0); 691 } 692