xref: /f-stack/freebsd/arm/allwinner/a10_hdmi.c (revision 22ce4aff)
1 /*-
2  * Copyright (c) 2016 Jared McNeill <[email protected]>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 /*
29  * Allwinner A10/A20 HDMI TX
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/rman.h>
39 #include <sys/condvar.h>
40 #include <sys/eventhandler.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 
44 #include <machine/bus.h>
45 
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48 
49 #include <dev/videomode/videomode.h>
50 #include <dev/videomode/edidvar.h>
51 
52 #include <dev/extres/clk/clk.h>
53 
54 #include "hdmi_if.h"
55 
56 #define	HDMI_CTRL		0x004
57 #define	CTRL_MODULE_EN		(1 << 31)
58 #define	HDMI_INT_STATUS		0x008
59 #define	HDMI_HPD		0x00c
60 #define	HPD_DET			(1 << 0)
61 #define	HDMI_VID_CTRL		0x010
62 #define	VID_CTRL_VIDEO_EN	(1 << 31)
63 #define	VID_CTRL_HDMI_MODE	(1 << 30)
64 #define	VID_CTRL_INTERLACE	(1 << 4)
65 #define	VID_CTRL_REPEATER_2X	(1 << 0)
66 #define	HDMI_VID_TIMING0	0x014
67 #define	VID_ACT_V(v)		(((v) - 1) << 16)
68 #define	VID_ACT_H(h)		(((h) - 1) << 0)
69 #define	HDMI_VID_TIMING1	0x018
70 #define	VID_VBP(vbp)		(((vbp) - 1) << 16)
71 #define	VID_HBP(hbp)		(((hbp) - 1) << 0)
72 #define	HDMI_VID_TIMING2	0x01c
73 #define	VID_VFP(vfp)		(((vfp) - 1) << 16)
74 #define	VID_HFP(hfp)		(((hfp) - 1) << 0)
75 #define	HDMI_VID_TIMING3	0x020
76 #define	VID_VSPW(vspw)		(((vspw) - 1) << 16)
77 #define	VID_HSPW(hspw)		(((hspw) - 1) << 0)
78 #define	HDMI_VID_TIMING4	0x024
79 #define	TX_CLOCK_NORMAL		0x03e00000
80 #define	VID_VSYNC_ACTSEL	(1 << 1)
81 #define	VID_HSYNC_ACTSEL	(1 << 0)
82 #define	HDMI_AUD_CTRL		0x040
83 #define	AUD_CTRL_EN		(1 << 31)
84 #define	AUD_CTRL_RST		(1 << 30)
85 #define	HDMI_ADMA_CTRL		0x044
86 #define	HDMI_ADMA_MODE		(1 << 31)
87 #define	HDMI_ADMA_MODE_DDMA	(0 << 31)
88 #define	HDMI_ADMA_MODE_NDMA	(1 << 31)
89 #define	HDMI_AUD_FMT		0x048
90 #define	AUD_FMT_CH(n)		((n) - 1)
91 #define	HDMI_PCM_CTRL		0x04c
92 #define	HDMI_AUD_CTS		0x050
93 #define	HDMI_AUD_N		0x054
94 #define	HDMI_AUD_CH_STATUS0	0x058
95 #define	CH_STATUS0_FS_FREQ	(0xf << 24)
96 #define	CH_STATUS0_FS_FREQ_48	(2 << 24)
97 #define	HDMI_AUD_CH_STATUS1	0x05c
98 #define	CH_STATUS1_WORD_LEN	(0x7 << 1)
99 #define	CH_STATUS1_WORD_LEN_16	(1 << 1)
100 #define	HDMI_AUDIO_RESET_RETRY	1000
101 #define	HDMI_AUDIO_CHANNELS	2
102 #define	HDMI_AUDIO_CHANNELMAP	0x76543210
103 #define	HDMI_AUDIO_N		6144	/* 48 kHz */
104 #define	HDMI_AUDIO_CTS(r, n)	((((r) * 10) * ((n) / 128)) / 480)
105 #define	HDMI_PADCTRL0		0x200
106 #define	PADCTRL0_BIASEN		(1 << 31)
107 #define	PADCTRL0_LDOCEN		(1 << 30)
108 #define	PADCTRL0_LDODEN		(1 << 29)
109 #define	PADCTRL0_PWENC		(1 << 28)
110 #define	PADCTRL0_PWEND		(1 << 27)
111 #define	PADCTRL0_PWENG		(1 << 26)
112 #define	PADCTRL0_CKEN		(1 << 25)
113 #define	PADCTRL0_SEN		(1 << 24)
114 #define	PADCTRL0_TXEN		(1 << 23)
115 #define	HDMI_PADCTRL1		0x204
116 #define	PADCTRL1_AMP_OPT	(1 << 23)
117 #define	PADCTRL1_AMPCK_OPT	(1 << 22)
118 #define	PADCTRL1_DMP_OPT	(1 << 21)
119 #define	PADCTRL1_EMP_OPT	(1 << 20)
120 #define	PADCTRL1_EMPCK_OPT	(1 << 19)
121 #define	PADCTRL1_PWSCK		(1 << 18)
122 #define	PADCTRL1_PWSDT		(1 << 17)
123 #define	PADCTRL1_REG_CSMPS	(1 << 16)
124 #define	PADCTRL1_REG_DEN	(1 << 15)
125 #define	PADCTRL1_REG_DENCK	(1 << 14)
126 #define	PADCTRL1_REG_PLRCK	(1 << 13)
127 #define	PADCTRL1_REG_EMP	(0x7 << 10)
128 #define	PADCTRL1_REG_EMP_EN	(0x2 << 10)
129 #define	PADCTRL1_REG_CD		(0x3 << 8)
130 #define	PADCTRL1_REG_CKSS	(0x3 << 6)
131 #define	PADCTRL1_REG_CKSS_1X	(0x1 << 6)
132 #define	PADCTRL1_REG_CKSS_2X	(0x0 << 6)
133 #define	PADCTRL1_REG_AMP	(0x7 << 3)
134 #define	PADCTRL1_REG_AMP_EN	(0x6 << 3)
135 #define	PADCTRL1_REG_PLR	(0x7 << 0)
136 #define	HDMI_PLLCTRL0		0x208
137 #define	PLLCTRL0_PLL_EN		(1 << 31)
138 #define	PLLCTRL0_BWS		(1 << 30)
139 #define	PLLCTRL0_HV_IS_33	(1 << 29)
140 #define	PLLCTRL0_LDO1_EN	(1 << 28)
141 #define	PLLCTRL0_LDO2_EN	(1 << 27)
142 #define	PLLCTRL0_SDIV2		(1 << 25)
143 #define	PLLCTRL0_VCO_GAIN	(0x1 << 22)
144 #define	PLLCTRL0_S		(0x7 << 17)
145 #define	PLLCTRL0_CP_S		(0xf << 12)
146 #define	PLLCTRL0_CS		(0x7 << 8)
147 #define	PLLCTRL0_PREDIV(x)	((x) << 4)
148 #define	PLLCTRL0_VCO_S		(0x8 << 0)
149 #define	HDMI_PLLDBG0		0x20c
150 #define	PLLDBG0_CKIN_SEL	(1 << 21)
151 #define	PLLDBG0_CKIN_SEL_PLL3	(0 << 21)
152 #define	PLLDBG0_CKIN_SEL_PLL7	(1 << 21)
153 #define	HDMI_PKTCTRL0		0x2f0
154 #define	HDMI_PKTCTRL1		0x2f4
155 #define	PKTCTRL_PACKET(n,t)	((t) << ((n) << 2))
156 #define	PKT_NULL		0
157 #define	PKT_GC			1
158 #define	PKT_AVI			2
159 #define	PKT_AI			3
160 #define	PKT_SPD			5
161 #define	PKT_END			15
162 #define	DDC_CTRL		0x500
163 #define	CTRL_DDC_EN		(1 << 31)
164 #define	CTRL_DDC_ACMD_START	(1 << 30)
165 #define	CTRL_DDC_FIFO_DIR	(1 << 8)
166 #define	CTRL_DDC_FIFO_DIR_READ	(0 << 8)
167 #define	CTRL_DDC_FIFO_DIR_WRITE	(1 << 8)
168 #define	CTRL_DDC_SWRST		(1 << 0)
169 #define	DDC_SLAVE_ADDR		0x504
170 #define	SLAVE_ADDR_SEG_SHIFT	24
171 #define	SLAVE_ADDR_EDDC_SHIFT	16
172 #define	SLAVE_ADDR_OFFSET_SHIFT	8
173 #define	SLAVE_ADDR_SHIFT	0
174 #define	DDC_INT_STATUS		0x50c
175 #define	INT_STATUS_XFER_DONE	(1 << 0)
176 #define	DDC_FIFO_CTRL		0x510
177 #define	FIFO_CTRL_CLEAR		(1 << 31)
178 #define	DDC_BYTE_COUNTER	0x51c
179 #define	DDC_COMMAND		0x520
180 #define	COMMAND_EOREAD		(4 << 0)
181 #define	DDC_CLOCK		0x528
182 #define	DDC_CLOCK_M		(1 << 3)
183 #define	DDC_CLOCK_N		(5 << 0)
184 #define	DDC_FIFO		0x518
185 #define	SWRST_DELAY		1000
186 #define	DDC_DELAY		1000
187 #define	DDC_RETRY		1000
188 #define	DDC_BLKLEN		16
189 #define	DDC_ADDR		0x50
190 #define	EDDC_ADDR		0x60
191 #define	EDID_LENGTH		128
192 #define	DDC_CTRL_LINE		0x540
193 #define	DDC_LINE_SCL_ENABLE	(1 << 8)
194 #define	DDC_LINE_SDA_ENABLE	(1 << 9)
195 #define	HDMI_ENABLE_DELAY	50000
196 #define	DDC_READ_RETRY		4
197 #define	EXT_TAG			0x00
198 #define	CEA_TAG_ID		0x02
199 #define	CEA_DTD			0x03
200 #define	DTD_BASIC_AUDIO		(1 << 6)
201 #define	CEA_REV			0x02
202 #define	CEA_DATA_OFF		0x03
203 #define	CEA_DATA_START		4
204 #define	BLOCK_TAG(x)		(((x) >> 5) & 0x7)
205 #define	BLOCK_TAG_VSDB		3
206 #define	BLOCK_LEN(x)		((x) & 0x1f)
207 #define	HDMI_VSDB_MINLEN	5
208 #define	HDMI_OUI		"\x03\x0c\x00"
209 #define	HDMI_OUI_LEN		3
210 #define	HDMI_DEFAULT_FREQ	297000000
211 
212 struct a10hdmi_softc {
213 	struct resource		*res;
214 
215 	struct intr_config_hook	mode_hook;
216 
217 	uint8_t			edid[EDID_LENGTH];
218 
219 	int			has_hdmi;
220 	int			has_audio;
221 
222 	clk_t			clk_ahb;
223 	clk_t			clk_hdmi;
224 	clk_t			clk_lcd;
225 };
226 
227 static struct resource_spec a10hdmi_spec[] = {
228 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
229 	{ -1, 0 }
230 };
231 
232 #define	HDMI_READ(sc, reg)		bus_read_4((sc)->res, (reg))
233 #define	HDMI_WRITE(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
234 
235 static void
a10hdmi_init(struct a10hdmi_softc * sc)236 a10hdmi_init(struct a10hdmi_softc *sc)
237 {
238 	/* Enable the HDMI module */
239 	HDMI_WRITE(sc, HDMI_CTRL, CTRL_MODULE_EN);
240 
241 	/* Configure PLL/DRV settings */
242 	HDMI_WRITE(sc, HDMI_PADCTRL0, PADCTRL0_BIASEN | PADCTRL0_LDOCEN |
243 	    PADCTRL0_LDODEN | PADCTRL0_PWENC | PADCTRL0_PWEND |
244 	    PADCTRL0_PWENG | PADCTRL0_CKEN | PADCTRL0_TXEN);
245 	HDMI_WRITE(sc, HDMI_PADCTRL1, PADCTRL1_AMP_OPT | PADCTRL1_AMPCK_OPT |
246 	    PADCTRL1_EMP_OPT | PADCTRL1_EMPCK_OPT | PADCTRL1_REG_DEN |
247 	    PADCTRL1_REG_DENCK | PADCTRL1_REG_EMP_EN | PADCTRL1_REG_AMP_EN);
248 
249 	/* Select PLL3 as input clock */
250 	HDMI_WRITE(sc, HDMI_PLLDBG0, PLLDBG0_CKIN_SEL_PLL3);
251 
252 	DELAY(HDMI_ENABLE_DELAY);
253 }
254 
255 static void
a10hdmi_hpd(void * arg)256 a10hdmi_hpd(void *arg)
257 {
258 	struct a10hdmi_softc *sc;
259 	device_t dev;
260 	uint32_t hpd;
261 
262 	dev = arg;
263 	sc = device_get_softc(dev);
264 
265 	hpd = HDMI_READ(sc, HDMI_HPD);
266 	if ((hpd & HPD_DET) == HPD_DET)
267 		EVENTHANDLER_INVOKE(hdmi_event, dev, HDMI_EVENT_CONNECTED);
268 
269 	config_intrhook_disestablish(&sc->mode_hook);
270 }
271 
272 static int
a10hdmi_probe(device_t dev)273 a10hdmi_probe(device_t dev)
274 {
275 	if (!ofw_bus_status_okay(dev))
276 		return (ENXIO);
277 
278 	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-hdmi"))
279 		return (ENXIO);
280 
281 	device_set_desc(dev, "Allwinner HDMI TX");
282 	return (BUS_PROBE_DEFAULT);
283 }
284 
285 static int
a10hdmi_attach(device_t dev)286 a10hdmi_attach(device_t dev)
287 {
288 	struct a10hdmi_softc *sc;
289 	int error;
290 
291 	sc = device_get_softc(dev);
292 
293 	if (bus_alloc_resources(dev, a10hdmi_spec, &sc->res)) {
294 		device_printf(dev, "cannot allocate resources for device\n");
295 		return (ENXIO);
296 	}
297 
298 	/* Setup clocks */
299 	error = clk_get_by_ofw_name(dev, 0, "ahb", &sc->clk_ahb);
300 	if (error != 0) {
301 		device_printf(dev, "cannot find ahb clock\n");
302 		return (error);
303 	}
304 	error = clk_get_by_ofw_name(dev, 0, "hdmi", &sc->clk_hdmi);
305 	if (error != 0) {
306 		device_printf(dev, "cannot find hdmi clock\n");
307 		return (error);
308 	}
309 	error = clk_get_by_ofw_name(dev, 0, "lcd", &sc->clk_lcd);
310 	if (error != 0) {
311 		device_printf(dev, "cannot find lcd clock\n");
312 	}
313 	/* Enable HDMI clock */
314 	error = clk_enable(sc->clk_hdmi);
315 	if (error != 0) {
316 		device_printf(dev, "cannot enable hdmi clock\n");
317 		return (error);
318 	}
319 	/* Gating AHB clock for HDMI */
320 	error = clk_enable(sc->clk_ahb);
321 	if (error != 0) {
322 		device_printf(dev, "cannot enable ahb gate\n");
323 		return (error);
324 	}
325 
326 	a10hdmi_init(sc);
327 
328 	sc->mode_hook.ich_func = a10hdmi_hpd;
329 	sc->mode_hook.ich_arg = dev;
330 
331 	error = config_intrhook_establish(&sc->mode_hook);
332 	if (error != 0)
333 		return (error);
334 
335 	return (0);
336 }
337 
338 static int
a10hdmi_ddc_xfer(struct a10hdmi_softc * sc,uint16_t addr,uint8_t seg,uint8_t off,int len)339 a10hdmi_ddc_xfer(struct a10hdmi_softc *sc, uint16_t addr, uint8_t seg,
340     uint8_t off, int len)
341 {
342 	uint32_t val;
343 	int retry;
344 
345 	/* Set FIFO direction to read */
346 	val = HDMI_READ(sc, DDC_CTRL);
347 	val &= ~CTRL_DDC_FIFO_DIR;
348 	val |= CTRL_DDC_FIFO_DIR_READ;
349 	HDMI_WRITE(sc, DDC_CTRL, val);
350 
351 	/* Setup DDC slave address */
352 	val = (addr << SLAVE_ADDR_SHIFT) | (seg << SLAVE_ADDR_SEG_SHIFT) |
353 	    (EDDC_ADDR << SLAVE_ADDR_EDDC_SHIFT) |
354 	    (off << SLAVE_ADDR_OFFSET_SHIFT);
355 	HDMI_WRITE(sc, DDC_SLAVE_ADDR, val);
356 
357 	/* Clear FIFO */
358 	val = HDMI_READ(sc, DDC_FIFO_CTRL);
359 	val |= FIFO_CTRL_CLEAR;
360 	HDMI_WRITE(sc, DDC_FIFO_CTRL, val);
361 
362 	/* Set transfer length */
363 	HDMI_WRITE(sc, DDC_BYTE_COUNTER, len);
364 
365 	/* Set command to "Explicit Offset Address Read" */
366 	HDMI_WRITE(sc, DDC_COMMAND, COMMAND_EOREAD);
367 
368 	/* Start transfer */
369 	val = HDMI_READ(sc, DDC_CTRL);
370 	val |= CTRL_DDC_ACMD_START;
371 	HDMI_WRITE(sc, DDC_CTRL, val);
372 
373 	/* Wait for command to start */
374 	retry = DDC_RETRY;
375 	while (--retry > 0) {
376 		val = HDMI_READ(sc, DDC_CTRL);
377 		if ((val & CTRL_DDC_ACMD_START) == 0)
378 			break;
379 		DELAY(DDC_DELAY);
380 	}
381 	if (retry == 0)
382 		return (ETIMEDOUT);
383 
384 	/* Ensure that the transfer completed */
385 	val = HDMI_READ(sc, DDC_INT_STATUS);
386 	if ((val & INT_STATUS_XFER_DONE) == 0)
387 		return (EIO);
388 
389 	return (0);
390 }
391 
392 static int
a10hdmi_ddc_read(struct a10hdmi_softc * sc,int block,uint8_t * edid)393 a10hdmi_ddc_read(struct a10hdmi_softc *sc, int block, uint8_t *edid)
394 {
395 	int resid, off, len, error;
396 	uint8_t *pbuf;
397 
398 	pbuf = edid;
399 	resid = EDID_LENGTH;
400 	off = (block & 1) ? EDID_LENGTH : 0;
401 
402 	while (resid > 0) {
403 		len = min(resid, DDC_BLKLEN);
404 		error = a10hdmi_ddc_xfer(sc, DDC_ADDR, block >> 1, off, len);
405 		if (error != 0)
406 			return (error);
407 
408 		bus_read_multi_1(sc->res, DDC_FIFO, pbuf, len);
409 
410 		pbuf += len;
411 		off += len;
412 		resid -= len;
413 	}
414 
415 	return (0);
416 }
417 
418 static int
a10hdmi_detect_hdmi_vsdb(uint8_t * edid)419 a10hdmi_detect_hdmi_vsdb(uint8_t *edid)
420 {
421 	int off, p, btag, blen;
422 
423 	if (edid[EXT_TAG] != CEA_TAG_ID)
424 		return (0);
425 
426 	off = edid[CEA_DATA_OFF];
427 
428 	/* CEA data block collection starts at byte 4 */
429 	if (off <= CEA_DATA_START)
430 		return (0);
431 
432 	/* Parse the CEA data blocks */
433 	for (p = CEA_DATA_START; p < off;) {
434 		btag = BLOCK_TAG(edid[p]);
435 		blen = BLOCK_LEN(edid[p]);
436 
437 		/* Make sure the length is sane */
438 		if (p + blen + 1 > off)
439 			break;
440 
441 		/* Look for a VSDB with the HDMI 24-bit IEEE registration ID */
442 		if (btag == BLOCK_TAG_VSDB && blen >= HDMI_VSDB_MINLEN &&
443 		    memcmp(&edid[p + 1], HDMI_OUI, HDMI_OUI_LEN) == 0)
444 			return (1);
445 
446 		/* Next data block */
447 		p += (1 + blen);
448 	}
449 
450 	return (0);
451 }
452 
453 static void
a10hdmi_detect_hdmi(struct a10hdmi_softc * sc,int * phdmi,int * paudio)454 a10hdmi_detect_hdmi(struct a10hdmi_softc *sc, int *phdmi, int *paudio)
455 {
456 	struct edid_info ei;
457 	uint8_t edid[EDID_LENGTH];
458 	int block;
459 
460 	*phdmi = *paudio = 0;
461 
462 	if (edid_parse(sc->edid, &ei) != 0)
463 		return;
464 
465 	/* Scan through extension blocks, looking for a CEA-861 block. */
466 	for (block = 1; block <= ei.edid_ext_block_count; block++) {
467 		if (a10hdmi_ddc_read(sc, block, edid) != 0)
468 			return;
469 
470 		if (a10hdmi_detect_hdmi_vsdb(edid) != 0) {
471 			*phdmi = 1;
472 			*paudio = ((edid[CEA_DTD] & DTD_BASIC_AUDIO) != 0);
473 			return;
474 		}
475 	}
476 }
477 
478 static int
a10hdmi_get_edid(device_t dev,uint8_t ** edid,uint32_t * edid_len)479 a10hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
480 {
481 	struct a10hdmi_softc *sc;
482 	int error, retry;
483 
484 	sc = device_get_softc(dev);
485 	retry = DDC_READ_RETRY;
486 
487 	while (--retry > 0) {
488 		/* I2C software reset */
489 		HDMI_WRITE(sc, DDC_FIFO_CTRL, 0);
490 		HDMI_WRITE(sc, DDC_CTRL, CTRL_DDC_EN | CTRL_DDC_SWRST);
491 		DELAY(SWRST_DELAY);
492 		if (HDMI_READ(sc, DDC_CTRL) & CTRL_DDC_SWRST) {
493 			device_printf(dev, "DDC software reset failed\n");
494 			return (ENXIO);
495 		}
496 
497 		/* Configure DDC clock */
498 		HDMI_WRITE(sc, DDC_CLOCK, DDC_CLOCK_M | DDC_CLOCK_N);
499 
500 		/* Enable SDA/SCL */
501 		HDMI_WRITE(sc, DDC_CTRL_LINE,
502 		    DDC_LINE_SCL_ENABLE | DDC_LINE_SDA_ENABLE);
503 
504 		/* Read EDID block */
505 		error = a10hdmi_ddc_read(sc, 0, sc->edid);
506 		if (error == 0) {
507 			*edid = sc->edid;
508 			*edid_len = sizeof(sc->edid);
509 			break;
510 		}
511 	}
512 
513 	if (error == 0)
514 		a10hdmi_detect_hdmi(sc, &sc->has_hdmi, &sc->has_audio);
515 	else
516 		sc->has_hdmi = sc->has_audio = 0;
517 
518 	return (error);
519 }
520 
521 static void
a10hdmi_set_audiomode(device_t dev,const struct videomode * mode)522 a10hdmi_set_audiomode(device_t dev, const struct videomode *mode)
523 {
524 	struct a10hdmi_softc *sc;
525 	uint32_t val;
526 	int retry;
527 
528 	sc = device_get_softc(dev);
529 
530 	/* Disable and reset audio module and wait for reset bit to clear */
531 	HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_RST);
532 	for (retry = HDMI_AUDIO_RESET_RETRY; retry > 0; retry--) {
533 		val = HDMI_READ(sc, HDMI_AUD_CTRL);
534 		if ((val & AUD_CTRL_RST) == 0)
535 			break;
536 	}
537 	if (retry == 0) {
538 		device_printf(dev, "timeout waiting for audio module\n");
539 		return;
540 	}
541 
542 	if (!sc->has_audio)
543 		return;
544 
545 	/* DMA and FIFO control */
546 	HDMI_WRITE(sc, HDMI_ADMA_CTRL, HDMI_ADMA_MODE_DDMA);
547 
548 	/* Audio format control (LPCM, S16LE, stereo) */
549 	HDMI_WRITE(sc, HDMI_AUD_FMT, AUD_FMT_CH(HDMI_AUDIO_CHANNELS));
550 
551 	/* Channel mappings */
552 	HDMI_WRITE(sc, HDMI_PCM_CTRL, HDMI_AUDIO_CHANNELMAP);
553 
554 	/* Clocks */
555 	HDMI_WRITE(sc, HDMI_AUD_CTS,
556 	    HDMI_AUDIO_CTS(mode->dot_clock, HDMI_AUDIO_N));
557 	HDMI_WRITE(sc, HDMI_AUD_N, HDMI_AUDIO_N);
558 
559 	/* Set sampling frequency to 48 kHz, word length to 16-bit */
560 	HDMI_WRITE(sc, HDMI_AUD_CH_STATUS0, CH_STATUS0_FS_FREQ_48);
561 	HDMI_WRITE(sc, HDMI_AUD_CH_STATUS1, CH_STATUS1_WORD_LEN_16);
562 
563 	/* Enable */
564 	HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_EN);
565 }
566 
567 static int
a10hdmi_get_tcon_config(struct a10hdmi_softc * sc,int * div,int * dbl)568 a10hdmi_get_tcon_config(struct a10hdmi_softc *sc, int *div, int *dbl)
569 {
570 	uint64_t lcd_fin, lcd_fout;
571 	clk_t clk_lcd_parent;
572 	const char *pname;
573 	int error;
574 
575 	error = clk_get_parent(sc->clk_lcd, &clk_lcd_parent);
576 	if (error != 0)
577 		return (error);
578 
579 	/* Get the LCD CH1 special clock 2 divider */
580 	error = clk_get_freq(sc->clk_lcd, &lcd_fout);
581 	if (error != 0)
582 		return (error);
583 	error = clk_get_freq(clk_lcd_parent, &lcd_fin);
584 	if (error != 0)
585 		return (error);
586 	*div = lcd_fin / lcd_fout;
587 
588 	/* Detect LCD CH1 special clock using a 1X or 2X source */
589 	/* XXX */
590 	pname = clk_get_name(clk_lcd_parent);
591 	if (strcmp(pname, "pll3") == 0 || strcmp(pname, "pll7") == 0)
592 		*dbl = 0;
593 	else
594 		*dbl = 1;
595 
596 	return (0);
597 }
598 
599 static int
a10hdmi_set_videomode(device_t dev,const struct videomode * mode)600 a10hdmi_set_videomode(device_t dev, const struct videomode *mode)
601 {
602 	struct a10hdmi_softc *sc;
603 	int error, clk_div, clk_dbl;
604 	int dblscan, hfp, hspw, hbp, vfp, vspw, vbp;
605 	uint32_t val;
606 
607 	sc = device_get_softc(dev);
608 	dblscan = !!(mode->flags & VID_DBLSCAN);
609 	hfp = mode->hsync_start - mode->hdisplay;
610 	hspw = mode->hsync_end - mode->hsync_start;
611 	hbp = mode->htotal - mode->hsync_start;
612 	vfp = mode->vsync_start - mode->vdisplay;
613 	vspw = mode->vsync_end - mode->vsync_start;
614 	vbp = mode->vtotal - mode->vsync_start;
615 
616 	error = a10hdmi_get_tcon_config(sc, &clk_div, &clk_dbl);
617 	if (error != 0) {
618 		device_printf(dev, "couldn't get tcon config: %d\n", error);
619 		return (error);
620 	}
621 
622 	/* Clear interrupt status */
623 	HDMI_WRITE(sc, HDMI_INT_STATUS, HDMI_READ(sc, HDMI_INT_STATUS));
624 
625 	/* Clock setup */
626 	val = HDMI_READ(sc, HDMI_PADCTRL1);
627 	val &= ~PADCTRL1_REG_CKSS;
628 	val |= (clk_dbl ? PADCTRL1_REG_CKSS_2X : PADCTRL1_REG_CKSS_1X);
629 	HDMI_WRITE(sc, HDMI_PADCTRL1, val);
630 	HDMI_WRITE(sc, HDMI_PLLCTRL0, PLLCTRL0_PLL_EN | PLLCTRL0_BWS |
631 	    PLLCTRL0_HV_IS_33 | PLLCTRL0_LDO1_EN | PLLCTRL0_LDO2_EN |
632 	    PLLCTRL0_SDIV2 | PLLCTRL0_VCO_GAIN | PLLCTRL0_S |
633 	    PLLCTRL0_CP_S | PLLCTRL0_CS | PLLCTRL0_PREDIV(clk_div) |
634 	    PLLCTRL0_VCO_S);
635 
636 	/* Setup display settings */
637 	if (bootverbose)
638 		device_printf(dev, "HDMI: %s, Audio: %s\n",
639 		    sc->has_hdmi ? "yes" : "no", sc->has_audio ? "yes" : "no");
640 	val = 0;
641 	if (sc->has_hdmi)
642 		val |= VID_CTRL_HDMI_MODE;
643 	if (mode->flags & VID_INTERLACE)
644 		val |= VID_CTRL_INTERLACE;
645 	if (mode->flags & VID_DBLSCAN)
646 		val |= VID_CTRL_REPEATER_2X;
647 	HDMI_WRITE(sc, HDMI_VID_CTRL, val);
648 
649 	/* Setup display timings */
650 	HDMI_WRITE(sc, HDMI_VID_TIMING0,
651 	    VID_ACT_V(mode->vdisplay) | VID_ACT_H(mode->hdisplay << dblscan));
652 	HDMI_WRITE(sc, HDMI_VID_TIMING1,
653 	    VID_VBP(vbp) | VID_HBP(hbp << dblscan));
654 	HDMI_WRITE(sc, HDMI_VID_TIMING2,
655 	    VID_VFP(vfp) | VID_HFP(hfp << dblscan));
656 	HDMI_WRITE(sc, HDMI_VID_TIMING3,
657 	    VID_VSPW(vspw) | VID_HSPW(hspw << dblscan));
658 	val = TX_CLOCK_NORMAL;
659 	if (mode->flags & VID_PVSYNC)
660 		val |= VID_VSYNC_ACTSEL;
661 	if (mode->flags & VID_PHSYNC)
662 		val |= VID_HSYNC_ACTSEL;
663 	HDMI_WRITE(sc, HDMI_VID_TIMING4, val);
664 
665 	/* This is an ordered list of infoframe packets that the HDMI
666 	 * transmitter will send. Transmit packets in the following order:
667 	 *  1. General control packet
668 	 *  2. AVI infoframe
669 	 *  3. Audio infoframe
670 	 * There are 2 registers with 4 slots each. The list is terminated
671 	 * with the special PKT_END marker.
672 	 */
673 	HDMI_WRITE(sc, HDMI_PKTCTRL0,
674 	    PKTCTRL_PACKET(0, PKT_GC) | PKTCTRL_PACKET(1, PKT_AVI) |
675 	    PKTCTRL_PACKET(2, PKT_AI) | PKTCTRL_PACKET(3, PKT_END));
676 	HDMI_WRITE(sc, HDMI_PKTCTRL1, 0);
677 
678 	/* Setup audio */
679 	a10hdmi_set_audiomode(dev, mode);
680 
681 	return (0);
682 }
683 
684 static int
a10hdmi_enable(device_t dev,int onoff)685 a10hdmi_enable(device_t dev, int onoff)
686 {
687 	struct a10hdmi_softc *sc;
688 	uint32_t val;
689 
690 	sc = device_get_softc(dev);
691 
692 	/* Enable or disable video output */
693 	val = HDMI_READ(sc, HDMI_VID_CTRL);
694 	if (onoff)
695 		val |= VID_CTRL_VIDEO_EN;
696 	else
697 		val &= ~VID_CTRL_VIDEO_EN;
698 	HDMI_WRITE(sc, HDMI_VID_CTRL, val);
699 
700 	return (0);
701 }
702 
703 static device_method_t a10hdmi_methods[] = {
704 	/* Device interface */
705 	DEVMETHOD(device_probe,		a10hdmi_probe),
706 	DEVMETHOD(device_attach,	a10hdmi_attach),
707 
708 	/* HDMI interface */
709 	DEVMETHOD(hdmi_get_edid,	a10hdmi_get_edid),
710 	DEVMETHOD(hdmi_set_videomode,	a10hdmi_set_videomode),
711 	DEVMETHOD(hdmi_enable,		a10hdmi_enable),
712 
713 	DEVMETHOD_END
714 };
715 
716 static driver_t a10hdmi_driver = {
717 	"a10hdmi",
718 	a10hdmi_methods,
719 	sizeof(struct a10hdmi_softc),
720 };
721 
722 static devclass_t a10hdmi_devclass;
723 
724 DRIVER_MODULE(a10hdmi, simplebus, a10hdmi_driver, a10hdmi_devclass, 0, 0);
725 MODULE_VERSION(a10hdmi, 1);
726