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