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