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