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