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