1 /*-
2 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
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
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
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
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
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
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
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
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
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
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
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
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
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
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 DRIVER_MODULE(a10hdmi, simplebus, a10hdmi_driver, 0, 0);
723 MODULE_VERSION(a10hdmi, 1);
Cache object: fc5ba086687a85a56cad9d4427644676
|