1 /* $OpenBSD: dwhdmi.c,v 1.2 2020/03/04 13:38:22 kettenis Exp $ */ 2 /* $NetBSD: dw_hdmi.c,v 1.7 2019/12/22 23:23:32 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/device.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 35 #include <dev/ic/dwhdmi.h> 36 37 #include <dev/i2c/i2cvar.h> 38 39 #ifdef notyet 40 #include <dev/audio/audio_dai.h> 41 #endif 42 43 #include <drm/drmP.h> 44 #include <drm/drm_crtc.h> 45 #include <drm/drm_crtc_helper.h> 46 #include <drm/drm_edid.h> 47 48 #define DDC_SEGMENT_ADDR 0x30 49 50 #define HDMI_DESIGN_ID 0x0000 51 #define HDMI_REVISION_ID 0x0001 52 #define HDMI_CONFIG0_ID 0x0004 53 #define HDMI_CONFIG0_ID_AUDI2S (1 << 4) 54 #define HDMI_CONFIG2_ID 0x0006 55 56 #define HDMI_IH_I2CM_STAT0 0x0105 57 #define HDMI_IH_I2CM_STAT0_DONE (1 << 1) 58 #define HDMI_IH_I2CM_STAT0_ERROR (1 << 0) 59 #define HDMI_IH_MUTE 0x01ff 60 #define HDMI_IH_MUTE_WAKEUP_INTERRUPT (1 << 1) 61 #define HDMI_IH_MUTE_ALL_INTERRUPT (1 << 0) 62 63 #define HDMI_TX_INVID0 0x0200 64 #define HDMI_TX_INVID0_VIDEO_MAPPING (0x1f << 0) 65 #define HDMI_TX_INVID0_VIDEO_MAPPING_DEFAULT (1 << 0) 66 #define HDMI_TX_INSTUFFING 0x0201 67 #define HDMI_TX_INSTUFFING_BCBDATA_STUFFING (1 << 2) 68 #define HDMI_TX_INSTUFFING_RCRDATA_STUFFING (1 << 1) 69 #define HDMI_TX_INSTUFFING_GYDATA_STUFFING (1 << 0) 70 #define HDMI_TX_GYDATA0 0x0202 71 #define HDMI_TX_GYDATA1 0x0203 72 #define HDMI_TX_RCRDATA0 0x0204 73 #define HDMI_TX_RCRDATA1 0x0205 74 #define HDMI_TX_BCBDATA0 0x0206 75 #define HDMI_TX_BCBDATA1 0x0207 76 77 #define HDMI_VP_STATUS 0x0800 78 #define HDMI_VP_PR_CD 0x0801 79 #define HDMI_VP_PR_CD_COLOR_DEPTH (0xf << 4) 80 #define HDMI_VP_PR_CD_COLOR_DEPTH_24 0 81 #define HDMI_VP_PR_CD_DESIRED_PR_FACTOR (0xf << 0) 82 #define HDMI_VP_PR_CD_DESIRED_PR_FACTOR_NONE 0 83 #define HDMI_VP_STUFF 0x0802 84 #define HDMI_VP_STUFF_IDEFAULT_PHASE (1 << 5) 85 #define HDMI_VP_STUFF_YCC422_STUFFING (1 << 2) 86 #define HDMI_VP_STUFF_PP_STUFFING (1 << 1) 87 #define HDMI_VP_STUFF_PR_STUFFING (1 << 0) 88 #define HDMI_VP_REMAP 0x0803 89 #define HDMI_VP_REMAP_YCC422_SIZE (0x3 << 0) 90 #define HDMI_VP_REMAP_YCC422_SIZE_16 0 91 #define HDMI_VP_CONF 0x0804 92 #define HDMI_VP_CONF_BYPASS_EN (1 << 6) 93 #define HDMI_VP_CONF_BYPASS_SELECT (1 << 2) 94 #define HDMI_VP_CONF_OUTPUT_SELECT (0x3 << 0) 95 #define HDMI_VP_CONF_OUTPUT_SELECT_BYPASS (2 << 0) 96 #define HDMI_VP_STAT 0x0805 97 #define HDMI_VP_INT 0x0806 98 #define HDMI_VP_MASK 0x0807 99 #define HDMI_VP_POL 0x0808 100 101 #define HDMI_FC_INVIDCONF 0x1000 102 #define HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY (1 << 6) 103 #define HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY (1 << 5) 104 #define HDMI_FC_INVIDCONF_DE_IN_POLARITY (1 << 4) 105 #define HDMI_FC_INVIDCONF_DVI_MODE (1 << 3) 106 #define HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC (1 << 1) 107 #define HDMI_FC_INVIDCONF_IN_I_P (1 << 0) 108 #define HDMI_FC_INHACTIV0 0x1001 109 #define HDMI_FC_INHACTIV1 0x1002 110 #define HDMI_FC_INHBLANK0 0x1003 111 #define HDMI_FC_INHBLANK1 0x1004 112 #define HDMI_FC_INVACTIV0 0x1005 113 #define HDMI_FC_INVACTIV1 0x1006 114 #define HDMI_FC_INVBLANK 0x1007 115 #define HDMI_FC_HSYNCINDELAY0 0x1008 116 #define HDMI_FC_HSYNCINDELAY1 0x1009 117 #define HDMI_FC_HSYNCINWIDTH0 0x100a 118 #define HDMI_FC_HSYNCINWIDTH1 0x100b 119 #define HDMI_FC_VSYNCINDELAY 0x100c 120 #define HDMI_FC_VSYNCINWIDTH 0x100d 121 #define HDMI_FC_CTRLDUR 0x1011 122 #define HDMI_FC_CTRLDUR_DEFAULT 12 123 #define HDMI_FC_EXCTRLDUR 0x1012 124 #define HDMI_FC_EXCTRLDUR_DEFAULT 32 125 #define HDMI_FC_EXCTRLSPAC 0x1013 126 #define HDMI_FC_EXCTRLSPAC_DEFAULT 1 127 #define HDMI_FC_CH0PREAM 0x1014 128 #define HDMI_FC_CH0PREAM_DEFAULT 0x0b 129 #define HDMI_FC_CH1PREAM 0x1015 130 #define HDMI_FC_CH1PREAM_DEFAULT 0x16 131 #define HDMI_FC_CH2PREAM 0x1016 132 #define HDMI_FC_CH2PREAM_DEFAULT 0x21 133 #define HDMI_FC_AUDCONF0 0x1025 134 #define HDMI_FC_AUDCONF1 0x1026 135 #define HDMI_FC_AUDCONF2 0x1027 136 #define HDMI_FC_AUDCONF3 0x1028 137 138 #define HDMI_PHY_CONF0 0x3000 139 #define HDMI_PHY_CONF0_PDZ (1 << 7) 140 #define HDMI_PHY_CONF0_ENTMDS (1 << 6) 141 #define HDMI_PHY_CONF0_SVSRET (1 << 5) 142 #define HDMI_PHY_CONF0_PDDQ (1 << 4) 143 #define HDMI_PHY_CONF0_TXPWRON (1 << 3) 144 #define HDMI_PHY_CONF0_ENHPDRXSENSE (1 << 2) 145 #define HDMI_PHY_CONF0_SELDATAENPOL (1 << 1) 146 #define HDMI_PHY_CONF0_SELDIPIF (1 << 0) 147 #define HDMI_PHY_STAT0 0x3004 148 #define HDMI_PHY_STAT0_RX_SENSE_3 (1 << 7) 149 #define HDMI_PHY_STAT0_RX_SENSE_2 (1 << 6) 150 #define HDMI_PHY_STAT0_RX_SENSE_1 (1 << 5) 151 #define HDMI_PHY_STAT0_RX_SENSE_0 (1 << 4) 152 #define HDMI_PHY_STAT0_HPD (1 << 1) 153 #define HDMI_PHY_STAT0_TX_PHY_LOCK (1 << 0) 154 155 #define HDMI_AUD_CONF0 0x3100 156 #define HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST (1 << 7) 157 #define HDMI_AUD_CONF0_I2S_SELECT (1 << 5) 158 #define HDMI_AUD_CONF0_I2S_IN_EN (0xf << 0) 159 #define HDMI_AUD_CONF1 0x3101 160 #define HDMI_AUD_CONF1_I2S_WIDTH (0x1f << 0) 161 #define HDMI_AUD_INT 0x3102 162 #define HDMI_AUD_CONF2 0x3103 163 #define HDMI_AUD_CONF2_INSERT_PCUV (1 << 2) 164 #define HDMI_AUD_CONF2_NLPCM (1 << 1) 165 #define HDMI_AUD_CONF2_HBR (1 << 0) 166 #define HDMI_AUD_INT1 0x3104 167 168 #define HDMI_AUD_N1 0x3200 169 #define HDMI_AUD_N2 0x3201 170 #define HDMI_AUD_N3 0x3202 171 #define HDMI_AUD_CTS1 0x3203 172 #define HDMI_AUD_CTS2 0x3204 173 #define HDMI_AUD_CTS3 0x3205 174 #define HDMI_AUD_INPUTCLKFS 0x3206 175 #define HDMI_AUD_INPUTCLKFS_IFSFACTOR (0x7 << 0) 176 177 #define HDMI_MC_CLKDIS 0x4001 178 #define HDMI_MC_CLKDIS_HDCPCLK_DISABLE (1 << 6) 179 #define HDMI_MC_CLKDIS_CECCLK_DISABLE (1 << 5) 180 #define HDMI_MC_CLKDIS_CSCCLK_DISABLE (1 << 4) 181 #define HDMI_MC_CLKDIS_AUDCLK_DISABLE (1 << 3) 182 #define HDMI_MC_CLKDIS_PREPCLK_DISABLE (1 << 2) 183 #define HDMI_MC_CLKDIS_TMDSCLK_DISABLE (1 << 1) 184 #define HDMI_MC_CLKDIS_PIXELCLK_DISABLE (1 << 0) 185 #define HDMI_MC_SWRSTZREQ 0x4002 186 #define HDMI_MC_SWRSTZREQ_CECSWRST_REQ __BIT(6) 187 #define HDMI_MC_SWRSTZREQ_PREPSWRST_REQ (1 << 2) 188 #define HDMI_MC_SWRSTZREQ_TMDSSWRST_REQ (1 << 1) 189 #define HDMI_MC_SWRSTZREQ_PIXELSWRST_REQ (1 << 0) 190 #define HDMI_MC_FLOWCTRL 0x4004 191 #define HDMI_MC_PHYRSTZ 0x4005 192 #define HDMI_MC_PHYRSTZ_ASSERT (1 << 0) 193 #define HDMI_MC_PHYRSTZ_DEASSERT 0 194 #define HDMI_MC_LOCKONCLOCK 0x4006 195 #define HDMI_MC_HEACPHY_RST 0x4007 196 197 #define HDMI_I2CM_SLAVE 0x7e00 198 #define HDMI_I2CM_ADDRESS 0x7e01 199 #define HDMI_I2CM_DATAO 0x7e02 200 #define HDMI_I2CM_DATAI 0x7e03 201 #define HDMI_I2CM_OPERATION 0x7e04 202 #define HDMI_I2CM_OPERATION_WR (1 << 4) 203 #define HDMI_I2CM_OPERATION_RD_EXT (1 << 1) 204 #define HDMI_I2CM_OPERATION_RD (1 << 0) 205 #define HDMI_I2CM_INT 0x7e05 206 #define HDMI_I2CM_INT_DONE_POL (1 << 3) 207 #define HDMI_I2CM_INT_DONE_MASK (1 << 2) 208 #define HDMI_I2CM_INT_DONE_INTERRUPT (1 << 1) 209 #define HDMI_I2CM_INT_DONE_STATUS (1 << 0) 210 #define HDMI_I2CM_INT_DEFAULT \ 211 (HDMI_I2CM_INT_DONE_POL| \ 212 HDMI_I2CM_INT_DONE_INTERRUPT| \ 213 HDMI_I2CM_INT_DONE_STATUS) 214 #define HDMI_I2CM_CTLINT 0x7e06 215 #define HDMI_I2CM_CTLINT_NACK_POL (1 << 7) 216 #define HDMI_I2CM_CTLINT_NACK_MASK (1 << 6) 217 #define HDMI_I2CM_CTLINT_NACK_INTERRUPT (1 << 5) 218 #define HDMI_I2CM_CTLINT_NACK_STATUS (1 << 4) 219 #define HDMI_I2CM_CTLINT_ARB_POL (1 << 3) 220 #define HDMI_I2CM_CTLINT_ARB_MASK (1 << 2) 221 #define HDMI_I2CM_CTLINT_ARB_INTERRUPT (1 << 1) 222 #define HDMI_I2CM_CTLINT_ARB_STATUS (1 << 0) 223 #define HDMI_I2CM_CTLINT_DEFAULT \ 224 (HDMI_I2CM_CTLINT_NACK_POL| \ 225 HDMI_I2CM_CTLINT_NACK_INTERRUPT| \ 226 HDMI_I2CM_CTLINT_NACK_STATUS| \ 227 HDMI_I2CM_CTLINT_ARB_POL| \ 228 HDMI_I2CM_CTLINT_ARB_INTERRUPT| \ 229 HDMI_I2CM_CTLINT_ARB_STATUS) 230 #define HDMI_I2CM_DIV 0x7e07 231 #define HDMI_I2CM_DIV_FAST_STD_MODE (1 << 3) 232 #define HDMI_I2CM_SEGADDR 0x7e08 233 #define HDMI_I2CM_SEGADDR_SEGADDR (0x7f << 0) 234 #define HDMI_I2CM_SOFTRSTZ 0x7e09 235 #define HDMI_I2CM_SOFTRSTZ_I2C_SOFTRST (1 << 0) 236 #define HDMI_I2CM_SEGPTR 0x7e0a 237 #define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x730c 238 #define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x730e 239 240 enum dwhdmi_dai_mixer_ctrl { 241 DWHDMI_DAI_OUTPUT_CLASS, 242 DWHDMI_DAI_INPUT_CLASS, 243 244 DWHDMI_DAI_OUTPUT_MASTER_VOLUME, 245 DWHDMI_DAI_INPUT_DAC_VOLUME, 246 247 DWHDMI_DAI_MIXER_CTRL_LAST 248 }; 249 250 int 251 dwhdmi_ddc_exec(void *priv, i2c_op_t op, i2c_addr_t addr, 252 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 253 { 254 struct dwhdmi_softc * const sc = priv; 255 uint8_t block, operation, val; 256 uint8_t *pbuf = buf; 257 int off, n, retry; 258 259 if (addr != DDC_ADDR || op != I2C_OP_READ_WITH_STOP || cmdlen == 0 || buf == NULL) { 260 printf("%s: bad args addr=%#x op=%#x cmdlen=%d buf=%p\n", 261 __func__, addr, op, (int)cmdlen, buf); 262 return ENXIO; 263 } 264 if (len > 256) { 265 printf("dwhdmi_ddc_exec: bad len %d\n", (int)len); 266 return ERANGE; 267 } 268 269 dwhdmi_write(sc, HDMI_I2CM_SOFTRSTZ, 0); 270 dwhdmi_write(sc, HDMI_IH_I2CM_STAT0, dwhdmi_read(sc, HDMI_IH_I2CM_STAT0)); 271 if (sc->sc_scl_hcnt) 272 dwhdmi_write(sc, HDMI_I2CM_SS_SCL_HCNT_0_ADDR, sc->sc_scl_hcnt); 273 if (sc->sc_scl_lcnt) 274 dwhdmi_write(sc, HDMI_I2CM_SS_SCL_LCNT_0_ADDR, sc->sc_scl_lcnt); 275 dwhdmi_write(sc, HDMI_I2CM_DIV, 0); 276 dwhdmi_write(sc, HDMI_I2CM_SLAVE, DDC_ADDR); 277 dwhdmi_write(sc, HDMI_I2CM_SEGADDR, DDC_SEGMENT_ADDR); 278 279 block = *(const uint8_t *)cmdbuf; 280 operation = block ? HDMI_I2CM_OPERATION_RD_EXT : HDMI_I2CM_OPERATION_RD; 281 off = (block & 1) ? 128 : 0; 282 283 dwhdmi_write(sc, HDMI_I2CM_SEGPTR, block >> 1); 284 285 for (n = 0; n < len; n++) { 286 dwhdmi_write(sc, HDMI_I2CM_ADDRESS, n + off); 287 dwhdmi_write(sc, HDMI_I2CM_OPERATION, operation); 288 for (retry = 10000; retry > 0; retry--) { 289 val = dwhdmi_read(sc, HDMI_IH_I2CM_STAT0); 290 if (val & HDMI_IH_I2CM_STAT0_ERROR) { 291 return EIO; 292 } 293 if (val & HDMI_IH_I2CM_STAT0_DONE) { 294 dwhdmi_write(sc, HDMI_IH_I2CM_STAT0, val); 295 break; 296 } 297 delay(1); 298 } 299 if (retry == 0) { 300 printf("dwhdmi_ddc_exec: timeout waiting for xfer, stat0=%#x\n", dwhdmi_read(sc, HDMI_IH_I2CM_STAT0)); 301 return ETIMEDOUT; 302 } 303 304 pbuf[n] = dwhdmi_read(sc, HDMI_I2CM_DATAI); 305 } 306 307 return 0; 308 } 309 310 uint8_t 311 dwhdmi_read(struct dwhdmi_softc *sc, bus_size_t reg) 312 { 313 uint8_t val; 314 315 switch (sc->sc_reg_width) { 316 case 1: 317 val = bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg); 318 break; 319 case 4: 320 val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg * 4) & 0xff; 321 break; 322 default: 323 val = 0; 324 break; 325 } 326 327 return val; 328 } 329 330 void 331 dwhdmi_write(struct dwhdmi_softc *sc, bus_size_t reg, uint8_t val) 332 { 333 switch (sc->sc_reg_width) { 334 case 1: 335 bus_space_write_1(sc->sc_bst, sc->sc_bsh, reg, val); 336 break; 337 case 4: 338 bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg * 4, val); 339 break; 340 } 341 } 342 343 void 344 dwhdmi_vp_init(struct dwhdmi_softc *sc) 345 { 346 uint8_t val; 347 348 /* Select 24-bits per pixel video, 8-bit packing mode and disable pixel repetition */ 349 val = HDMI_VP_PR_CD_COLOR_DEPTH_24 << 4 | 350 HDMI_VP_PR_CD_DESIRED_PR_FACTOR_NONE << 0; 351 dwhdmi_write(sc, HDMI_VP_PR_CD, val); 352 353 /* Configure stuffing */ 354 val = HDMI_VP_STUFF_IDEFAULT_PHASE | 355 HDMI_VP_STUFF_YCC422_STUFFING | 356 HDMI_VP_STUFF_PP_STUFFING | 357 HDMI_VP_STUFF_PR_STUFFING; 358 dwhdmi_write(sc, HDMI_VP_STUFF, val); 359 360 /* Set YCC422 remap to 16-bit input video */ 361 val = HDMI_VP_REMAP_YCC422_SIZE_16 << 0; 362 dwhdmi_write(sc, HDMI_VP_REMAP, val); 363 364 /* Configure video packetizer */ 365 val = HDMI_VP_CONF_BYPASS_EN | 366 HDMI_VP_CONF_BYPASS_SELECT | 367 HDMI_VP_CONF_OUTPUT_SELECT_BYPASS; 368 dwhdmi_write(sc, HDMI_VP_CONF, val); 369 } 370 371 void 372 dwhdmi_tx_init(struct dwhdmi_softc *sc) 373 { 374 uint8_t val; 375 376 /* Disable internal data enable generator and set default video mapping */ 377 val = HDMI_TX_INVID0_VIDEO_MAPPING_DEFAULT; 378 dwhdmi_write(sc, HDMI_TX_INVID0, val); 379 380 /* Enable video sampler stuffing */ 381 val = HDMI_TX_INSTUFFING_BCBDATA_STUFFING | 382 HDMI_TX_INSTUFFING_RCRDATA_STUFFING | 383 HDMI_TX_INSTUFFING_GYDATA_STUFFING; 384 dwhdmi_write(sc, HDMI_TX_INSTUFFING, val); 385 } 386 387 int 388 dwhdmi_cea_mode_uses_fractional_vblank(uint8_t vic) 389 { 390 const uint8_t match[] = { 5, 6, 7, 10, 11, 20, 21, 22 }; 391 u_int n; 392 393 for (n = 0; n < nitems(match); n++) 394 if (match[n] == vic) 395 return true; 396 397 return false; 398 } 399 400 void 401 dwhdmi_fc_init(struct dwhdmi_softc *sc, struct drm_display_mode *mode) 402 { 403 struct dwhdmi_connector *dwhdmi_connector = &sc->sc_connector; 404 uint8_t val; 405 406 const uint8_t vic = drm_match_cea_mode(mode); 407 const uint16_t inhactiv = mode->crtc_hdisplay; 408 const uint16_t inhblank = mode->crtc_htotal - mode->crtc_hdisplay; 409 const uint16_t invactiv = mode->crtc_vdisplay; 410 const uint8_t invblank = mode->crtc_vtotal - mode->crtc_vdisplay; 411 const uint16_t hsyncindelay = mode->crtc_hsync_start - mode->crtc_hdisplay; 412 const uint16_t hsyncinwidth = mode->crtc_hsync_end - mode->crtc_hsync_start; 413 const uint8_t vsyncindelay = mode->crtc_vsync_start - mode->crtc_vdisplay; 414 const uint8_t vsyncinwidth = mode->crtc_vsync_end - mode->crtc_vsync_start; 415 416 /* Input video configuration for frame composer */ 417 val = HDMI_FC_INVIDCONF_DE_IN_POLARITY; 418 if ((mode->flags & DRM_MODE_FLAG_PVSYNC) != 0) 419 val |= HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY; 420 if ((mode->flags & DRM_MODE_FLAG_PHSYNC) != 0) 421 val |= HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY; 422 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) != 0) 423 val |= HDMI_FC_INVIDCONF_IN_I_P; 424 if (dwhdmi_connector->hdmi_monitor) 425 val |= HDMI_FC_INVIDCONF_DVI_MODE; 426 if (dwhdmi_cea_mode_uses_fractional_vblank(vic)) 427 val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC; 428 dwhdmi_write(sc, HDMI_FC_INVIDCONF, val); 429 430 /* Input video mode timings */ 431 dwhdmi_write(sc, HDMI_FC_INHACTIV0, inhactiv & 0xff); 432 dwhdmi_write(sc, HDMI_FC_INHACTIV1, inhactiv >> 8); 433 dwhdmi_write(sc, HDMI_FC_INHBLANK0, inhblank & 0xff); 434 dwhdmi_write(sc, HDMI_FC_INHBLANK1, inhblank >> 8); 435 dwhdmi_write(sc, HDMI_FC_INVACTIV0, invactiv & 0xff); 436 dwhdmi_write(sc, HDMI_FC_INVACTIV1, invactiv >> 8); 437 dwhdmi_write(sc, HDMI_FC_INVBLANK, invblank); 438 dwhdmi_write(sc, HDMI_FC_HSYNCINDELAY0, hsyncindelay & 0xff); 439 dwhdmi_write(sc, HDMI_FC_HSYNCINDELAY1, hsyncindelay >> 8); 440 dwhdmi_write(sc, HDMI_FC_HSYNCINWIDTH0, hsyncinwidth & 0xff); 441 dwhdmi_write(sc, HDMI_FC_HSYNCINWIDTH1, hsyncinwidth >> 8); 442 dwhdmi_write(sc, HDMI_FC_VSYNCINDELAY, vsyncindelay); 443 dwhdmi_write(sc, HDMI_FC_VSYNCINWIDTH, vsyncinwidth); 444 445 /* Setup control period minimum durations */ 446 dwhdmi_write(sc, HDMI_FC_CTRLDUR, HDMI_FC_CTRLDUR_DEFAULT); 447 dwhdmi_write(sc, HDMI_FC_EXCTRLDUR, HDMI_FC_EXCTRLDUR_DEFAULT); 448 dwhdmi_write(sc, HDMI_FC_EXCTRLSPAC, HDMI_FC_EXCTRLSPAC_DEFAULT); 449 450 /* Setup channel preamble filters */ 451 dwhdmi_write(sc, HDMI_FC_CH0PREAM, HDMI_FC_CH0PREAM_DEFAULT); 452 dwhdmi_write(sc, HDMI_FC_CH1PREAM, HDMI_FC_CH1PREAM_DEFAULT); 453 dwhdmi_write(sc, HDMI_FC_CH2PREAM, HDMI_FC_CH2PREAM_DEFAULT); 454 } 455 456 void 457 dwhdmi_mc_init(struct dwhdmi_softc *sc) 458 { 459 uint8_t val; 460 u_int n, iter; 461 462 /* Bypass colour space converter */ 463 dwhdmi_write(sc, HDMI_MC_FLOWCTRL, 0); 464 465 /* Enable TMDS, pixel, and (if required) audio sampler clocks */ 466 val = HDMI_MC_CLKDIS_HDCPCLK_DISABLE | 467 HDMI_MC_CLKDIS_CECCLK_DISABLE | 468 HDMI_MC_CLKDIS_CSCCLK_DISABLE | 469 HDMI_MC_CLKDIS_PREPCLK_DISABLE; 470 dwhdmi_write(sc, HDMI_MC_CLKDIS, val); 471 472 /* Soft reset TMDS */ 473 val = 0xff & ~HDMI_MC_SWRSTZREQ_TMDSSWRST_REQ; 474 dwhdmi_write(sc, HDMI_MC_SWRSTZREQ, val); 475 476 iter = sc->sc_version == 0x130a ? 4 : 1; 477 478 val = dwhdmi_read(sc, HDMI_FC_INVIDCONF); 479 for (n = 0; n < iter; n++) 480 dwhdmi_write(sc, HDMI_FC_INVIDCONF, val); 481 } 482 483 void 484 dwhdmi_mc_disable(struct dwhdmi_softc *sc) 485 { 486 /* Disable clocks */ 487 dwhdmi_write(sc, HDMI_MC_CLKDIS, 0xff); 488 } 489 490 void 491 dwhdmi_audio_init(struct dwhdmi_softc *sc) 492 { 493 uint8_t val; 494 u_int n; 495 496 /* The following values are for 48 kHz */ 497 switch (sc->sc_curmode.clock) { 498 case 25170: 499 n = 6864; 500 break; 501 case 74170: 502 n = 11648; 503 break; 504 case 148350: 505 n = 5824; 506 break; 507 default: 508 n = 6144; 509 break; 510 } 511 512 /* Use automatic CTS generation */ 513 dwhdmi_write(sc, HDMI_AUD_CTS1, 0); 514 dwhdmi_write(sc, HDMI_AUD_CTS2, 0); 515 dwhdmi_write(sc, HDMI_AUD_CTS3, 0); 516 517 /* Set N factor for audio clock regeneration */ 518 dwhdmi_write(sc, HDMI_AUD_N1, n & 0xff); 519 dwhdmi_write(sc, HDMI_AUD_N2, (n >> 8) & 0xff); 520 dwhdmi_write(sc, HDMI_AUD_N3, (n >> 16) & 0xff); 521 522 val = dwhdmi_read(sc, HDMI_AUD_CONF0); 523 val |= HDMI_AUD_CONF0_I2S_SELECT; /* XXX i2s mode */ 524 val &= ~HDMI_AUD_CONF0_I2S_IN_EN; 525 val |= (1 << 0); /* XXX 2ch */ 526 dwhdmi_write(sc, HDMI_AUD_CONF0, val); 527 528 val = (16 << 0); 529 dwhdmi_write(sc, HDMI_AUD_CONF1, val); 530 531 dwhdmi_write(sc, HDMI_AUD_INPUTCLKFS, 4); /* XXX 64 FS */ 532 533 dwhdmi_write(sc, HDMI_FC_AUDCONF0, 1 << 4); /* XXX 2ch */ 534 dwhdmi_write(sc, HDMI_FC_AUDCONF1, 0); 535 dwhdmi_write(sc, HDMI_FC_AUDCONF2, 0); 536 dwhdmi_write(sc, HDMI_FC_AUDCONF3, 0); 537 538 val = dwhdmi_read(sc, HDMI_MC_CLKDIS); 539 val &= ~HDMI_MC_CLKDIS_PREPCLK_DISABLE; 540 dwhdmi_write(sc, HDMI_MC_CLKDIS, val); 541 } 542 543 enum drm_connector_status 544 dwhdmi_connector_detect(struct drm_connector *connector, bool force) 545 { 546 struct dwhdmi_connector *dwhdmi_connector = to_dwhdmi_connector(connector); 547 struct dwhdmi_softc * const sc = dwhdmi_connector->sc; 548 549 if (sc->sc_detect != NULL) 550 return sc->sc_detect(sc, force); 551 552 return connector_status_connected; 553 } 554 555 void 556 dwhdmi_connector_destroy(struct drm_connector *connector) 557 { 558 drm_connector_unregister(connector); 559 drm_connector_cleanup(connector); 560 } 561 562 const struct drm_connector_funcs dwhdmi_connector_funcs = { 563 .dpms = drm_helper_connector_dpms, 564 .detect = dwhdmi_connector_detect, 565 .fill_modes = drm_helper_probe_single_connector_modes, 566 .destroy = dwhdmi_connector_destroy, 567 }; 568 569 int 570 dwhdmi_connector_get_modes(struct drm_connector *connector) 571 { 572 struct dwhdmi_connector *dwhdmi_connector = to_dwhdmi_connector(connector); 573 struct dwhdmi_softc * const sc = dwhdmi_connector->sc; 574 struct i2c_adapter ddc; 575 struct edid *edid; 576 int error = 0; 577 578 memset(&ddc, 0, sizeof(ddc)); 579 ddc.ic = *sc->sc_ic; 580 581 edid = drm_get_edid(connector, &ddc); 582 if (edid) { 583 dwhdmi_connector->hdmi_monitor = drm_detect_hdmi_monitor(edid); 584 dwhdmi_connector->monitor_audio = drm_detect_monitor_audio(edid); 585 drm_connector_update_edid_property(connector, edid); 586 error = drm_add_edid_modes(connector, edid); 587 kfree(edid); 588 } else { 589 dwhdmi_connector->hdmi_monitor = false; 590 dwhdmi_connector->monitor_audio = false; 591 } 592 593 return error; 594 } 595 596 struct drm_encoder * 597 dwhdmi_connector_best_encoder(struct drm_connector *connector) 598 { 599 int enc_id = connector->encoder_ids[0]; 600 struct drm_mode_object *obj; 601 struct drm_encoder *encoder = NULL; 602 603 if (enc_id) { 604 obj = drm_mode_object_find(connector->dev, NULL, enc_id, 605 DRM_MODE_OBJECT_ENCODER); 606 if (obj == NULL) 607 return NULL; 608 encoder = obj_to_encoder(obj); 609 } 610 611 return encoder; 612 } 613 614 const struct drm_connector_helper_funcs dwhdmi_connector_helper_funcs = { 615 .get_modes = dwhdmi_connector_get_modes, 616 .best_encoder = dwhdmi_connector_best_encoder, 617 }; 618 619 int 620 dwhdmi_bridge_attach(struct drm_bridge *bridge) 621 { 622 struct dwhdmi_softc * const sc = bridge->driver_private; 623 struct dwhdmi_connector *dwhdmi_connector = &sc->sc_connector; 624 struct drm_connector *connector = &dwhdmi_connector->base; 625 int error; 626 627 dwhdmi_connector->sc = sc; 628 629 connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; 630 connector->interlace_allowed = 0; 631 connector->doublescan_allowed = 0; 632 633 drm_connector_init(bridge->dev, connector, &dwhdmi_connector_funcs, 634 DRM_MODE_CONNECTOR_HDMIA); 635 drm_connector_helper_add(connector, &dwhdmi_connector_helper_funcs); 636 637 error = drm_connector_attach_encoder(connector, bridge->encoder); 638 if (error != 0) 639 return error; 640 641 return drm_connector_register(connector); 642 } 643 644 void 645 dwhdmi_bridge_enable(struct drm_bridge *bridge) 646 { 647 struct dwhdmi_softc * const sc = bridge->driver_private; 648 649 dwhdmi_vp_init(sc); 650 dwhdmi_fc_init(sc, &sc->sc_curmode); 651 652 if (sc->sc_enable) 653 sc->sc_enable(sc); 654 655 dwhdmi_tx_init(sc); 656 dwhdmi_mc_init(sc); 657 658 if (sc->sc_connector.monitor_audio) 659 dwhdmi_audio_init(sc); 660 } 661 662 void 663 dwhdmi_bridge_pre_enable(struct drm_bridge *bridge) 664 { 665 } 666 667 void 668 dwhdmi_bridge_disable(struct drm_bridge *bridge) 669 { 670 struct dwhdmi_softc * const sc = bridge->driver_private; 671 672 if (sc->sc_disable) 673 sc->sc_disable(sc); 674 675 dwhdmi_mc_disable(sc); 676 } 677 678 void 679 dwhdmi_bridge_post_disable(struct drm_bridge *bridge) 680 { 681 } 682 683 void 684 dwhdmi_bridge_mode_set(struct drm_bridge *bridge, 685 struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) 686 { 687 struct dwhdmi_softc *sc = bridge->driver_private; 688 689 if (sc->sc_mode_set) 690 sc->sc_mode_set(sc, mode, adjusted_mode); 691 692 sc->sc_curmode = *adjusted_mode; 693 } 694 695 enum drm_mode_status 696 dwhdmi_bridge_mode_valid(struct drm_bridge *bridge, 697 const struct drm_display_mode *mode) 698 { 699 struct dwhdmi_softc *sc = bridge->driver_private; 700 701 if (mode->flags & DRM_MODE_FLAG_DBLCLK) 702 return MODE_BAD; 703 704 if (sc->sc_mode_valid) 705 return sc->sc_mode_valid(sc, mode); 706 707 return MODE_OK; 708 } 709 710 const struct drm_bridge_funcs dwhdmi_bridge_funcs = { 711 .attach = dwhdmi_bridge_attach, 712 .enable = dwhdmi_bridge_enable, 713 .pre_enable = dwhdmi_bridge_pre_enable, 714 .disable = dwhdmi_bridge_disable, 715 .post_disable = dwhdmi_bridge_post_disable, 716 .mode_set = dwhdmi_bridge_mode_set, 717 .mode_valid = dwhdmi_bridge_mode_valid, 718 }; 719 720 #ifdef notyet 721 722 static int 723 dwhdmi_dai_set_format(audio_dai_tag_t dai, u_int format) 724 { 725 return 0; 726 } 727 728 static int 729 dwhdmi_dai_add_device(audio_dai_tag_t dai, audio_dai_tag_t aux) 730 { 731 /* Not supported */ 732 return 0; 733 } 734 735 static void 736 dwhdmi_audio_swvol_codec(audio_filter_arg_t *arg) 737 { 738 struct dwhdmi_softc * const sc = arg->context; 739 const aint_t *src; 740 aint_t *dst; 741 u_int sample_count; 742 u_int i; 743 744 src = arg->src; 745 dst = arg->dst; 746 sample_count = arg->count * arg->srcfmt->channels; 747 for (i = 0; i < sample_count; i++) { 748 aint2_t v = (aint2_t)(*src++); 749 v = v * sc->sc_swvol / 255; 750 *dst++ = (aint_t)v; 751 } 752 } 753 754 static int 755 dwhdmi_audio_set_format(void *priv, int setmode, 756 const audio_params_t *play, const audio_params_t *rec, 757 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 758 { 759 struct dwhdmi_softc * const sc = priv; 760 761 pfil->codec = dwhdmi_audio_swvol_codec; 762 pfil->context = sc; 763 764 return 0; 765 } 766 767 static int 768 dwhdmi_audio_set_port(void *priv, mixer_ctrl_t *mc) 769 { 770 struct dwhdmi_softc * const sc = priv; 771 772 switch (mc->dev) { 773 case DWHDMI_DAI_OUTPUT_MASTER_VOLUME: 774 case DWHDMI_DAI_INPUT_DAC_VOLUME: 775 sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 776 return 0; 777 default: 778 return ENXIO; 779 } 780 } 781 782 static int 783 dwhdmi_audio_get_port(void *priv, mixer_ctrl_t *mc) 784 { 785 struct dwhdmi_softc * const sc = priv; 786 787 switch (mc->dev) { 788 case DWHDMI_DAI_OUTPUT_MASTER_VOLUME: 789 case DWHDMI_DAI_INPUT_DAC_VOLUME: 790 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_swvol; 791 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_swvol; 792 return 0; 793 default: 794 return ENXIO; 795 } 796 } 797 798 static int 799 dwhdmi_audio_query_devinfo(void *priv, mixer_devinfo_t *di) 800 { 801 switch (di->index) { 802 case DWHDMI_DAI_OUTPUT_CLASS: 803 di->mixer_class = di->index; 804 strcpy(di->label.name, AudioCoutputs); 805 di->type = AUDIO_MIXER_CLASS; 806 di->next = di->prev = AUDIO_MIXER_LAST; 807 return 0; 808 809 case DWHDMI_DAI_INPUT_CLASS: 810 di->mixer_class = di->index; 811 strcpy(di->label.name, AudioCinputs); 812 di->type = AUDIO_MIXER_CLASS; 813 di->next = di->prev = AUDIO_MIXER_LAST; 814 return 0; 815 816 case DWHDMI_DAI_OUTPUT_MASTER_VOLUME: 817 di->mixer_class = DWHDMI_DAI_OUTPUT_CLASS; 818 strcpy(di->label.name, AudioNmaster); 819 di->un.v.delta = 1; 820 di->un.v.num_channels = 2; 821 strcpy(di->un.v.units.name, AudioNvolume); 822 di->type = AUDIO_MIXER_VALUE; 823 di->next = di->prev = AUDIO_MIXER_LAST; 824 return 0; 825 826 case DWHDMI_DAI_INPUT_DAC_VOLUME: 827 di->mixer_class = DWHDMI_DAI_INPUT_CLASS; 828 strcpy(di->label.name, AudioNdac); 829 di->un.v.delta = 1; 830 di->un.v.num_channels = 2; 831 strcpy(di->un.v.units.name, AudioNvolume); 832 di->type = AUDIO_MIXER_VALUE; 833 di->next = di->prev = AUDIO_MIXER_LAST; 834 return 0; 835 836 default: 837 return ENXIO; 838 } 839 } 840 841 static const struct audio_hw_if dwhdmi_dai_hw_if = { 842 .set_format = dwhdmi_audio_set_format, 843 .set_port = dwhdmi_audio_set_port, 844 .get_port = dwhdmi_audio_get_port, 845 .query_devinfo = dwhdmi_audio_query_devinfo, 846 }; 847 848 #endif 849 850 int 851 dwhdmi_attach(struct dwhdmi_softc *sc) 852 { 853 uint8_t val; 854 855 if (sc->sc_reg_width != 1 && sc->sc_reg_width != 4) { 856 printf("%s: unsupported register width %d\n", 857 sc->sc_dev.dv_xname, sc->sc_reg_width); 858 return EINVAL; 859 } 860 861 sc->sc_version = dwhdmi_read(sc, HDMI_DESIGN_ID); 862 sc->sc_version <<= 8; 863 sc->sc_version |= dwhdmi_read(sc, HDMI_REVISION_ID); 864 865 sc->sc_phytype = dwhdmi_read(sc, HDMI_CONFIG2_ID); 866 867 printf("%s: version %x.%03x, phytype 0x%02x\n", sc->sc_dev.dv_xname, 868 sc->sc_version >> 12, sc->sc_version & 0xfff, 869 sc->sc_phytype); 870 871 #ifdef notyet 872 sc->sc_swvol = 255; 873 #endif 874 875 /* 876 * If a DDC i2c bus tag is provided by the caller, use it. Otherwise, 877 * use the I2C master built-in to DWC HDMI. 878 */ 879 if (sc->sc_ic == NULL) { 880 struct i2c_controller *ic = &sc->sc_ic_builtin; 881 882 memset(ic, 0, sizeof(*ic)); 883 ic->ic_cookie = sc; 884 ic->ic_exec = dwhdmi_ddc_exec; 885 sc->sc_ic = ic; 886 } 887 888 /* 889 * Enable HPD on internal PHY 890 */ 891 if ((sc->sc_flags & DWHDMI_USE_INTERNAL_PHY) != 0) { 892 val = dwhdmi_read(sc, HDMI_PHY_CONF0); 893 val |= HDMI_PHY_CONF0_ENHPDRXSENSE; 894 dwhdmi_write(sc, HDMI_PHY_CONF0, val); 895 } 896 897 #ifdef notyet 898 /* 899 * Initialize audio DAI 900 */ 901 sc->sc_dai.dai_set_format = dwhdmi_dai_set_format; 902 sc->sc_dai.dai_add_device = dwhdmi_dai_add_device; 903 sc->sc_dai.dai_hw_if = &dwhdmi_dai_hw_if; 904 sc->sc_dai.dai_dev = sc->sc_dev; 905 sc->sc_dai.dai_priv = sc; 906 #endif 907 908 return 0; 909 } 910 911 int 912 dwhdmi_bind(struct dwhdmi_softc *sc, struct drm_encoder *encoder) 913 { 914 int error; 915 916 sc->sc_bridge.driver_private = sc; 917 sc->sc_bridge.funcs = &dwhdmi_bridge_funcs; 918 sc->sc_bridge.encoder = encoder; 919 920 error = drm_bridge_attach(encoder, &sc->sc_bridge, NULL); 921 if (error != 0) 922 return EIO; 923 924 encoder->bridge = &sc->sc_bridge; 925 926 return 0; 927 } 928