xref: /freebsd/sys/dev/hdmi/dwc_hdmi.c (revision 9ff086544d5f85b58349e28ed36a9811b8fe5cf9)
1 /*-
2  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 /*
31  * HDMI core module
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 #include <sys/bus.h>
40 #include <sys/rman.h>
41 
42 #include <machine/bus.h>
43 
44 #include <dev/videomode/videomode.h>
45 #include <dev/videomode/edidvar.h>
46 
47 #include <dev/iicbus/iicbus.h>
48 #include <dev/iicbus/iiconf.h>
49 
50 #include <dev/hdmi/dwc_hdmi.h>
51 #include <dev/hdmi/dwc_hdmireg.h>
52 
53 #include "hdmi_if.h"
54 
55 #define	I2C_DDC_ADDR	(0x50 << 1)
56 #define	EDID_LENGTH	0x80
57 
58 static void
59 dwc_hdmi_phy_wait_i2c_done(struct dwc_hdmi_softc *sc, int msec)
60 {
61 	uint8_t val;
62 
63 	val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) &
64 	    (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
65 	while (val == 0) {
66 		pause("HDMI_PHY", hz/100);
67 		msec -= 10;
68 		if (msec <= 0)
69 			return;
70 		val = RD1(sc, HDMI_IH_I2CMPHY_STAT0) &
71 		    (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
72 	}
73 }
74 
75 static void
76 dwc_hdmi_phy_i2c_write(struct dwc_hdmi_softc *sc, unsigned short data,
77     unsigned char addr)
78 {
79 
80 	/* clear DONE and ERROR flags */
81 	WR1(sc, HDMI_IH_I2CMPHY_STAT0,
82 	    HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
83 	WR1(sc, HDMI_PHY_I2CM_ADDRESS_ADDR, addr);
84 	WR1(sc, HDMI_PHY_I2CM_DATAO_1_ADDR, ((data >> 8) & 0xff));
85 	WR1(sc, HDMI_PHY_I2CM_DATAO_0_ADDR, ((data >> 0) & 0xff));
86 	WR1(sc, HDMI_PHY_I2CM_OPERATION_ADDR, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE);
87 	dwc_hdmi_phy_wait_i2c_done(sc, 1000);
88 }
89 
90 static void
91 dwc_hdmi_disable_overflow_interrupts(struct dwc_hdmi_softc *sc)
92 {
93 	WR1(sc, HDMI_IH_MUTE_FC_STAT2, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK);
94 	WR1(sc, HDMI_FC_MASK2,
95 	    HDMI_FC_MASK2_LOW_PRI | HDMI_FC_MASK2_HIGH_PRI);
96 }
97 
98 static void
99 dwc_hdmi_av_composer(struct dwc_hdmi_softc *sc)
100 {
101 	uint8_t inv_val;
102 	int is_dvi;
103 	int hblank, vblank, hsync_len, hfp, vfp;
104 
105 	/* Set up HDMI_FC_INVIDCONF */
106 	inv_val = ((sc->sc_mode.flags & VID_PVSYNC) ?
107 		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
108 		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
109 
110 	inv_val |= ((sc->sc_mode.flags & VID_PHSYNC) ?
111 		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
112 		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
113 
114 	inv_val |= HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH;
115 
116 	inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ?
117 			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
118 			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
119 
120 	inv_val |= ((sc->sc_mode.flags & VID_INTERLACE) ?
121 		HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
122 		HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
123 
124 	/* TODO: implement HDMI part */
125 	is_dvi = 1;
126 	inv_val |= (is_dvi ?
127 		HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
128 		HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
129 
130 	WR1(sc, HDMI_FC_INVIDCONF, inv_val);
131 
132 	/* Set up horizontal active pixel region width */
133 	WR1(sc, HDMI_FC_INHACTV1, sc->sc_mode.hdisplay >> 8);
134 	WR1(sc, HDMI_FC_INHACTV0, sc->sc_mode.hdisplay);
135 
136 	/* Set up vertical blanking pixel region width */
137 	WR1(sc, HDMI_FC_INVACTV1, sc->sc_mode.vdisplay >> 8);
138 	WR1(sc, HDMI_FC_INVACTV0, sc->sc_mode.vdisplay);
139 
140 	/* Set up horizontal blanking pixel region width */
141 	hblank = sc->sc_mode.htotal - sc->sc_mode.hdisplay;
142 	WR1(sc, HDMI_FC_INHBLANK1, hblank >> 8);
143 	WR1(sc, HDMI_FC_INHBLANK0, hblank);
144 
145 	/* Set up vertical blanking pixel region width */
146 	vblank = sc->sc_mode.vtotal - sc->sc_mode.vdisplay;
147 	WR1(sc, HDMI_FC_INVBLANK, vblank);
148 
149 	/* Set up HSYNC active edge delay width (in pixel clks) */
150 	hfp = sc->sc_mode.hsync_start - sc->sc_mode.hdisplay;
151 	WR1(sc, HDMI_FC_HSYNCINDELAY1, hfp >> 8);
152 	WR1(sc, HDMI_FC_HSYNCINDELAY0, hfp);
153 
154 	/* Set up VSYNC active edge delay (in pixel clks) */
155 	vfp = sc->sc_mode.vsync_start - sc->sc_mode.vdisplay;
156 	WR1(sc, HDMI_FC_VSYNCINDELAY, vfp);
157 
158 	hsync_len = (sc->sc_mode.hsync_end - sc->sc_mode.hsync_start);
159 	/* Set up HSYNC active pulse width (in pixel clks) */
160 	WR1(sc, HDMI_FC_HSYNCINWIDTH1, hsync_len >> 8);
161 	WR1(sc, HDMI_FC_HSYNCINWIDTH0, hsync_len);
162 
163 	/* Set up VSYNC active edge delay (in pixel clks) */
164 	WR1(sc, HDMI_FC_VSYNCINWIDTH, (sc->sc_mode.vsync_end - sc->sc_mode.vsync_start));
165 }
166 
167 static void
168 dwc_hdmi_phy_enable_power(struct dwc_hdmi_softc *sc, uint8_t enable)
169 {
170 	uint8_t reg;
171 
172 	reg = RD1(sc, HDMI_PHY_CONF0);
173 	reg &= ~HDMI_PHY_CONF0_PDZ_MASK;
174 	reg |= (enable << HDMI_PHY_CONF0_PDZ_OFFSET);
175 	WR1(sc, HDMI_PHY_CONF0, reg);
176 }
177 
178 static void
179 dwc_hdmi_phy_enable_tmds(struct dwc_hdmi_softc *sc, uint8_t enable)
180 {
181 	uint8_t reg;
182 
183 	reg = RD1(sc, HDMI_PHY_CONF0);
184 	reg &= ~HDMI_PHY_CONF0_ENTMDS_MASK;
185 	reg |= (enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
186 	WR1(sc, HDMI_PHY_CONF0, reg);
187 }
188 
189 static void
190 dwc_hdmi_phy_gen2_pddq(struct dwc_hdmi_softc *sc, uint8_t enable)
191 {
192 	uint8_t reg;
193 
194 	reg = RD1(sc, HDMI_PHY_CONF0);
195 	reg &= ~HDMI_PHY_CONF0_GEN2_PDDQ_MASK;
196 	reg |= (enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
197 	WR1(sc, HDMI_PHY_CONF0, reg);
198 }
199 
200 static void
201 dwc_hdmi_phy_gen2_txpwron(struct dwc_hdmi_softc *sc, uint8_t enable)
202 {
203 	uint8_t reg;
204 
205 	reg = RD1(sc, HDMI_PHY_CONF0);
206 	reg &= ~HDMI_PHY_CONF0_GEN2_TXPWRON_MASK;
207 	reg |= (enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
208 	WR1(sc, HDMI_PHY_CONF0, reg);
209 }
210 
211 static void
212 dwc_hdmi_phy_sel_data_en_pol(struct dwc_hdmi_softc *sc, uint8_t enable)
213 {
214 	uint8_t reg;
215 
216 	reg = RD1(sc, HDMI_PHY_CONF0);
217 	reg &= ~HDMI_PHY_CONF0_SELDATAENPOL_MASK;
218 	reg |= (enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
219 	WR1(sc, HDMI_PHY_CONF0, reg);
220 }
221 
222 static void
223 dwc_hdmi_phy_sel_interface_control(struct dwc_hdmi_softc *sc, uint8_t enable)
224 {
225 	uint8_t reg;
226 
227 	reg = RD1(sc, HDMI_PHY_CONF0);
228 	reg &= ~HDMI_PHY_CONF0_SELDIPIF_MASK;
229 	reg |= (enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
230 	WR1(sc, HDMI_PHY_CONF0, reg);
231 }
232 
233 static inline void
234 dwc_hdmi_phy_test_clear(struct dwc_hdmi_softc *sc, unsigned char bit)
235 {
236 	uint8_t val;
237 
238 	val = RD1(sc, HDMI_PHY_TST0);
239 	val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
240 	val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
241 		HDMI_PHY_TST0_TSTCLR_MASK;
242 	WR1(sc, HDMI_PHY_TST0, val);
243 }
244 
245 static void
246 dwc_hdmi_clear_overflow(struct dwc_hdmi_softc *sc)
247 {
248 	int count;
249 	uint8_t val;
250 
251 	/* TMDS software reset */
252 	WR1(sc, HDMI_MC_SWRSTZ, (uint8_t)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ);
253 
254 	val = RD1(sc, HDMI_FC_INVIDCONF);
255 
256 	for (count = 0 ; count < 4 ; count++)
257 		WR1(sc, HDMI_FC_INVIDCONF, val);
258 }
259 
260 static int
261 dwc_hdmi_phy_configure(struct dwc_hdmi_softc *sc)
262 {
263 	uint8_t val;
264 	uint8_t msec;
265 
266 	WR1(sc, HDMI_MC_FLOWCTRL, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS);
267 
268 	/* gen2 tx power off */
269 	dwc_hdmi_phy_gen2_txpwron(sc, 0);
270 
271 	/* gen2 pddq */
272 	dwc_hdmi_phy_gen2_pddq(sc, 1);
273 
274 	/* PHY reset */
275 	WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_DEASSERT);
276 	WR1(sc, HDMI_MC_PHYRSTZ, HDMI_MC_PHYRSTZ_ASSERT);
277 
278 	WR1(sc, HDMI_MC_HEACPHY_RST, HDMI_MC_HEACPHY_RST_ASSERT);
279 
280 	dwc_hdmi_phy_test_clear(sc, 1);
281 	WR1(sc, HDMI_PHY_I2CM_SLAVE_ADDR, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2);
282 	dwc_hdmi_phy_test_clear(sc, 0);
283 
284 	/*
285 	 * Following initialization are for 8bit per color case
286 	 */
287 
288 	/*
289 	 * PLL/MPLL config, see section 24.7.22 in TRM
290 	 *  config, see section 24.7.22
291 	 */
292 	if (sc->sc_mode.dot_clock*1000 <= 45250000) {
293 		dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_45_25, HDMI_PHY_I2C_CPCE_CTRL);
294 		dwc_hdmi_phy_i2c_write(sc, GMPCTRL_45_25, HDMI_PHY_I2C_GMPCTRL);
295 	} else if (sc->sc_mode.dot_clock*1000 <= 92500000) {
296 		dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_92_50, HDMI_PHY_I2C_CPCE_CTRL);
297 		dwc_hdmi_phy_i2c_write(sc, GMPCTRL_92_50, HDMI_PHY_I2C_GMPCTRL);
298 	} else if (sc->sc_mode.dot_clock*1000 <= 185000000) {
299 		dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_185, HDMI_PHY_I2C_CPCE_CTRL);
300 		dwc_hdmi_phy_i2c_write(sc, GMPCTRL_185, HDMI_PHY_I2C_GMPCTRL);
301 	} else {
302 		dwc_hdmi_phy_i2c_write(sc, CPCE_CTRL_370, HDMI_PHY_I2C_CPCE_CTRL);
303 		dwc_hdmi_phy_i2c_write(sc, GMPCTRL_370, HDMI_PHY_I2C_GMPCTRL);
304 	}
305 
306 	/*
307 	 * Values described in TRM section 34.9.2 PLL/MPLL Generic
308 	 *    Configuration Settings. Table 34-23.
309 	 */
310 	if (sc->sc_mode.dot_clock*1000 <= 54000000) {
311 		dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
312 	} else if (sc->sc_mode.dot_clock*1000 <= 58400000) {
313 		dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
314 	} else if (sc->sc_mode.dot_clock*1000 <= 72000000) {
315 		dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
316 	} else if (sc->sc_mode.dot_clock*1000 <= 74250000) {
317 		dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
318 	} else if (sc->sc_mode.dot_clock*1000 <= 118800000) {
319 		dwc_hdmi_phy_i2c_write(sc, 0x091c, HDMI_PHY_I2C_CURRCTRL);
320 	} else if (sc->sc_mode.dot_clock*1000 <= 216000000) {
321 		dwc_hdmi_phy_i2c_write(sc, 0x06dc, HDMI_PHY_I2C_CURRCTRL);
322 	} else {
323 		panic("Unsupported mode\n");
324 	}
325 
326 	dwc_hdmi_phy_i2c_write(sc, 0x0000, HDMI_PHY_I2C_PLLPHBYCTRL);
327 	dwc_hdmi_phy_i2c_write(sc, MSM_CTRL_FB_CLK, HDMI_PHY_I2C_MSM_CTRL);
328 	/* RESISTANCE TERM 133 Ohm */
329 	dwc_hdmi_phy_i2c_write(sc, TXTERM_133, HDMI_PHY_I2C_TXTERM);
330 
331 	/* REMOVE CLK TERM */
332 	dwc_hdmi_phy_i2c_write(sc, CKCALCTRL_OVERRIDE, HDMI_PHY_I2C_CKCALCTRL);
333 
334 	if (sc->sc_mode.dot_clock*1000 > 148500000) {
335 		dwc_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON |
336 		    CKSYMTXCTRL_TX_TRBON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL);
337 		dwc_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(9) | VLEVCTRL_CK_LVL(9),
338 		    HDMI_PHY_I2C_VLEVCTRL);
339 	} else {
340 		dwc_hdmi_phy_i2c_write(sc,CKSYMTXCTRL_OVERRIDE | CKSYMTXCTRL_TX_SYMON |
341 		    CKSYMTXCTRL_TX_TRAON | CKSYMTXCTRL_TX_CK_SYMON, HDMI_PHY_I2C_CKSYMTXCTRL);
342 		dwc_hdmi_phy_i2c_write(sc, VLEVCTRL_TX_LVL(13) | VLEVCTRL_CK_LVL(13),
343 		    HDMI_PHY_I2C_VLEVCTRL);
344 	}
345 
346 	dwc_hdmi_phy_enable_power(sc, 1);
347 
348 	/* toggle TMDS enable */
349 	dwc_hdmi_phy_enable_tmds(sc, 0);
350 	dwc_hdmi_phy_enable_tmds(sc, 1);
351 
352 	/* gen2 tx power on */
353 	dwc_hdmi_phy_gen2_txpwron(sc, 1);
354 	dwc_hdmi_phy_gen2_pddq(sc, 0);
355 
356 	/*Wait for PHY PLL lock */
357 	msec = 4;
358 	val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
359 	while (val == 0) {
360 		DELAY(1000);
361 		if (msec-- == 0) {
362 			device_printf(sc->sc_dev, "PHY PLL not locked\n");
363 			return (-1);
364 		}
365 		val = RD1(sc, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
366 	}
367 
368 	return true;
369 }
370 
371 static void
372 dwc_hdmi_phy_init(struct dwc_hdmi_softc *sc)
373 {
374 	int i;
375 
376 	/* HDMI Phy spec says to do the phy initialization sequence twice */
377 	for (i = 0 ; i < 2 ; i++) {
378 		dwc_hdmi_phy_sel_data_en_pol(sc, 1);
379 		dwc_hdmi_phy_sel_interface_control(sc, 0);
380 		dwc_hdmi_phy_enable_tmds(sc, 0);
381 		dwc_hdmi_phy_enable_power(sc, 0);
382 
383 		/* Enable CSC */
384 		dwc_hdmi_phy_configure(sc);
385 	}
386 }
387 
388 static void
389 dwc_hdmi_enable_video_path(struct dwc_hdmi_softc *sc)
390 {
391 	uint8_t clkdis;
392 
393 	/*
394 	 * Control period timing
395 	 * Values are minimal according to HDMI spec 1.4a
396 	 */
397 	WR1(sc, HDMI_FC_CTRLDUR, 12);
398 	WR1(sc, HDMI_FC_EXCTRLDUR, 32);
399 	WR1(sc, HDMI_FC_EXCTRLSPAC, 1);
400 
401 	/*
402 	 * Bits to fill data lines not used to transmit preamble
403 	 * for channels 0, 1, and 2 respectively
404 	 */
405 	WR1(sc, HDMI_FC_CH0PREAM, 0x0B);
406 	WR1(sc, HDMI_FC_CH1PREAM, 0x16);
407 	WR1(sc, HDMI_FC_CH2PREAM, 0x21);
408 
409 	/* Save CEC clock */
410 	clkdis = RD1(sc, HDMI_MC_CLKDIS) & HDMI_MC_CLKDIS_CECCLK_DISABLE;
411 	clkdis |= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
412 
413 	/* Enable pixel clock and tmds data path */
414 	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
415 	WR1(sc, HDMI_MC_CLKDIS, clkdis);
416 
417 	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
418 	WR1(sc, HDMI_MC_CLKDIS, clkdis);
419 }
420 
421 static void
422 dwc_hdmi_video_packetize(struct dwc_hdmi_softc *sc)
423 {
424 	unsigned int color_depth = 0;
425 	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16BIT;
426 	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
427 	uint8_t val;
428 
429 	output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
430 	color_depth = 4;
431 
432 	/* set the packetizer registers */
433 	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
434 		HDMI_VP_PR_CD_COLOR_DEPTH_MASK);
435 	WR1(sc, HDMI_VP_PR_CD, val);
436 
437 	val = RD1(sc, HDMI_VP_STUFF);
438 	val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
439 	val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
440 	WR1(sc, HDMI_VP_STUFF, val);
441 
442 	val = RD1(sc, HDMI_VP_CONF);
443 	val &= ~(HDMI_VP_CONF_PR_EN_MASK |
444 		HDMI_VP_CONF_BYPASS_SELECT_MASK);
445 	val |= HDMI_VP_CONF_PR_EN_DISABLE |
446 		HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
447 	WR1(sc, HDMI_VP_CONF, val);
448 
449 	val = RD1(sc, HDMI_VP_STUFF);
450 	val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
451 	val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
452 	WR1(sc, HDMI_VP_STUFF, val);
453 
454 	WR1(sc, HDMI_VP_REMAP, remap_size);
455 
456 	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
457 		val = RD1(sc, HDMI_VP_CONF);
458 		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
459 			HDMI_VP_CONF_PP_EN_ENMASK |
460 			HDMI_VP_CONF_YCC422_EN_MASK);
461 		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
462 			HDMI_VP_CONF_PP_EN_ENABLE |
463 			HDMI_VP_CONF_YCC422_EN_DISABLE;
464 		WR1(sc, HDMI_VP_CONF, val);
465 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
466 		val = RD1(sc, HDMI_VP_CONF);
467 		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
468 			HDMI_VP_CONF_PP_EN_ENMASK |
469 			HDMI_VP_CONF_YCC422_EN_MASK);
470 		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
471 			HDMI_VP_CONF_PP_EN_DISABLE |
472 			HDMI_VP_CONF_YCC422_EN_ENABLE;
473 		WR1(sc, HDMI_VP_CONF, val);
474 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
475 		val = RD1(sc, HDMI_VP_CONF);
476 		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
477 			HDMI_VP_CONF_PP_EN_ENMASK |
478 			HDMI_VP_CONF_YCC422_EN_MASK);
479 		val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
480 			HDMI_VP_CONF_PP_EN_DISABLE |
481 			HDMI_VP_CONF_YCC422_EN_DISABLE;
482 		WR1(sc, HDMI_VP_CONF, val);
483 	} else {
484 		return;
485 	}
486 
487 	val = RD1(sc, HDMI_VP_STUFF);
488 	val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
489 		HDMI_VP_STUFF_YCC422_STUFFING_MASK);
490 	val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
491 		HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
492 	WR1(sc, HDMI_VP_STUFF, val);
493 
494 	val = RD1(sc, HDMI_VP_CONF);
495 	val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
496 	val |= output_select;
497 	WR1(sc, HDMI_VP_CONF, val);
498 }
499 
500 static void
501 dwc_hdmi_video_sample(struct dwc_hdmi_softc *sc)
502 {
503 	int color_format;
504 	uint8_t val;
505 
506 	color_format = 0x01;
507 	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
508 		((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
509 		HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
510 	WR1(sc, HDMI_TX_INVID0, val);
511 
512 	/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
513 	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
514 		HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
515 		HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
516 	WR1(sc, HDMI_TX_INSTUFFING, val);
517 	WR1(sc, HDMI_TX_GYDATA0, 0x0);
518 	WR1(sc, HDMI_TX_GYDATA1, 0x0);
519 	WR1(sc, HDMI_TX_RCRDATA0, 0x0);
520 	WR1(sc, HDMI_TX_RCRDATA1, 0x0);
521 	WR1(sc, HDMI_TX_BCBDATA0, 0x0);
522 	WR1(sc, HDMI_TX_BCBDATA1, 0x0);
523 }
524 
525 static void
526 dwc_hdmi_tx_hdcp_config(struct dwc_hdmi_softc *sc)
527 {
528 	uint8_t de, val;
529 
530 	de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
531 
532 	/* Disable RX detect */
533 	val = RD1(sc, HDMI_A_HDCPCFG0);
534 	val &= ~HDMI_A_HDCPCFG0_RXDETECT_MASK;
535 	val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
536 	WR1(sc, HDMI_A_HDCPCFG0, val);
537 
538 	/* Set polarity */
539 	val = RD1(sc, HDMI_A_VIDPOLCFG);
540 	val &= ~HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
541 	val |= de;
542 	WR1(sc, HDMI_A_VIDPOLCFG, val);
543 
544 	/* Disable encryption */
545 	val = RD1(sc, HDMI_A_HDCPCFG1);
546 	val &= ~HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
547 	val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
548 	WR1(sc, HDMI_A_HDCPCFG1, val);
549 }
550 
551 static int
552 dwc_hdmi_set_mode(struct dwc_hdmi_softc *sc)
553 {
554 
555 	dwc_hdmi_disable_overflow_interrupts(sc);
556 	dwc_hdmi_av_composer(sc);
557 	dwc_hdmi_phy_init(sc);
558 	dwc_hdmi_enable_video_path(sc);
559 	/* TODO: AVI infoframes */
560 	dwc_hdmi_video_packetize(sc);
561 	/* TODO:  dwc_hdmi_video_csc(sc); */
562 	dwc_hdmi_video_sample(sc);
563 	dwc_hdmi_tx_hdcp_config(sc);
564 	dwc_hdmi_clear_overflow(sc);
565 
566 	return (0);
567 }
568 
569 static int
570 hdmi_edid_read(struct dwc_hdmi_softc *sc, uint8_t **edid, uint32_t *edid_len)
571 {
572 	device_t i2c_dev;
573 	int result;
574 	uint8_t addr = 0;
575 	struct iic_msg msg[] = {
576 		{ 0, IIC_M_WR, 1, &addr },
577 		{ 0, IIC_M_RD, EDID_LENGTH, NULL}
578 	};
579 
580 	*edid = NULL;
581 	*edid_len = 0;
582 	i2c_dev = NULL;
583 
584 	if (sc->sc_get_i2c_dev != NULL)
585 		i2c_dev = sc->sc_get_i2c_dev(sc->sc_dev);
586 	if (!i2c_dev) {
587 		device_printf(sc->sc_dev, "no DDC device found\n");
588 		return (ENXIO);
589 	}
590 
591 	device_printf(sc->sc_dev, "reading EDID from %s, addr %02x\n",
592 	    device_get_nameunit(i2c_dev), I2C_DDC_ADDR/2);
593 
594 	msg[0].slave = I2C_DDC_ADDR;
595 	msg[1].slave = I2C_DDC_ADDR;
596 	msg[1].buf = sc->sc_edid;
597 
598 	result = iicbus_request_bus(i2c_dev, sc->sc_dev, IIC_INTRWAIT);
599 
600 	if (result) {
601 		device_printf(sc->sc_dev, "failed to request i2c bus: %d\n", result);
602 		return (result);
603 	}
604 
605 	result = iicbus_transfer(i2c_dev, msg, 2);
606 	iicbus_release_bus(i2c_dev, sc->sc_dev);
607 
608 	if (result) {
609 		device_printf(sc->sc_dev, "i2c transfer failed: %d\n", result);
610 		return (result);
611 	} else {
612 		*edid_len = sc->sc_edid_len;
613 		*edid = sc->sc_edid;
614 	}
615 
616 	return (result);
617 }
618 
619 static void
620 dwc_hdmi_detect_cable(void *arg)
621 {
622 	struct dwc_hdmi_softc *sc;
623 	uint32_t stat;
624 
625 	sc = arg;
626 
627 	stat = RD1(sc, HDMI_IH_PHY_STAT0);
628 	if ((stat & HDMI_IH_PHY_STAT0_HPD) != 0) {
629 		EVENTHANDLER_INVOKE(hdmi_event, sc->sc_dev,
630 		    HDMI_EVENT_CONNECTED);
631 	}
632 
633 	/* Finished with the interrupt hook */
634 	config_intrhook_disestablish(&sc->sc_mode_hook);
635 }
636 
637 int
638 dwc_hdmi_init(device_t dev)
639 {
640 	struct dwc_hdmi_softc *sc;
641 	int err;
642 
643 	sc = device_get_softc(dev);
644 	err = 0;
645 
646 	sc->sc_edid = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO);
647 	sc->sc_edid_len = EDID_LENGTH;
648 
649 	device_printf(sc->sc_dev, "HDMI controller %02x:%02x:%02x:%02x\n",
650 	    RD1(sc, HDMI_DESIGN_ID), RD1(sc, HDMI_REVISION_ID),
651 	    RD1(sc, HDMI_PRODUCT_ID0), RD1(sc, HDMI_PRODUCT_ID1));
652 
653 	WR1(sc, HDMI_PHY_POL0, HDMI_PHY_POL0_HPD);
654 	WR1(sc, HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD);
655 
656 	sc->sc_mode_hook.ich_func = dwc_hdmi_detect_cable;
657 	sc->sc_mode_hook.ich_arg = sc;
658 	if (config_intrhook_establish(&sc->sc_mode_hook) != 0) {
659 		err = ENOMEM;
660 		goto out;
661 	}
662 
663 out:
664 
665 	if (err != 0) {
666 		free(sc->sc_edid, M_DEVBUF);
667 		sc->sc_edid = NULL;
668 	}
669 
670 	return (err);
671 }
672 
673 int
674 dwc_hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
675 {
676 
677 	return (hdmi_edid_read(device_get_softc(dev), edid, edid_len));
678 }
679 
680 int
681 dwc_hdmi_set_videomode(device_t dev, const struct videomode *mode)
682 {
683 	struct dwc_hdmi_softc *sc;
684 
685 	sc = device_get_softc(dev);
686 	memcpy(&sc->sc_mode, mode, sizeof(*mode));
687 
688 	dwc_hdmi_set_mode(sc);
689 
690 	return (0);
691 }
692