xref: /f-stack/freebsd/arm/allwinner/a10_fb.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 Framebuffer
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 #include <sys/fbio.h>
44 #include <vm/vm.h>
45 #include <vm/vm_extern.h>
46 #include <vm/vm_kern.h>
47 #include <vm/pmap.h>
48 
49 #include <machine/bus.h>
50 
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53 
54 #include <dev/videomode/videomode.h>
55 #include <dev/videomode/edidvar.h>
56 
57 #include <dev/extres/clk/clk.h>
58 #include <dev/extres/hwreset/hwreset.h>
59 
60 #include "fb_if.h"
61 #include "hdmi_if.h"
62 
63 #define	FB_DEFAULT_W	800
64 #define	FB_DEFAULT_H	600
65 #define	FB_DEFAULT_REF	60
66 #define	FB_BPP		32
67 #define	FB_ALIGN	0x1000
68 
69 #define	HDMI_ENABLE_DELAY	20000
70 #define	DEBE_FREQ		300000000
71 
72 #define	DOT_CLOCK_TO_HZ(c)	((c) * 1000)
73 
74 /* Display backend */
75 #define	DEBE_REG_START		0x800
76 #define	DEBE_REG_END		0x1000
77 #define	DEBE_REG_WIDTH		4
78 #define	DEBE_MODCTL		0x800
79 #define	MODCTL_ITLMOD_EN	(1 << 28)
80 #define	MODCTL_OUT_SEL_MASK	(0x7 << 20)
81 #define	MODCTL_OUT_SEL(sel)	((sel) << 20)
82 #define	OUT_SEL_LCD		0
83 #define	MODCTL_LAY0_EN		(1 << 8)
84 #define	MODCTL_START_CTL	(1 << 1)
85 #define	MODCTL_EN		(1 << 0)
86 #define	DEBE_DISSIZE		0x808
87 #define	DIS_HEIGHT(h)		(((h) - 1) << 16)
88 #define	DIS_WIDTH(w)		(((w) - 1) << 0)
89 #define	DEBE_LAYSIZE0		0x810
90 #define	LAY_HEIGHT(h)		(((h) - 1) << 16)
91 #define	LAY_WIDTH(w)		(((w) - 1) << 0)
92 #define	DEBE_LAYCOOR0		0x820
93 #define	LAY_XCOOR(x)		((x) << 16)
94 #define	LAY_YCOOR(y)		((y) << 0)
95 #define	DEBE_LAYLINEWIDTH0	0x840
96 #define	DEBE_LAYFB_L32ADD0	0x850
97 #define	LAYFB_L32ADD(pa)	((pa) << 3)
98 #define	DEBE_LAYFB_H4ADD	0x860
99 #define	LAY0FB_H4ADD(pa)	((pa) >> 29)
100 #define	DEBE_REGBUFFCTL		0x870
101 #define	REGBUFFCTL_LOAD		(1 << 0)
102 #define	DEBE_ATTCTL1		0x8a0
103 #define	ATTCTL1_FBFMT(fmt)	((fmt) << 8)
104 #define	FBFMT_XRGB8888		9
105 #define	ATTCTL1_FBPS(ps)	((ps) << 0)
106 #define	FBPS_32BPP_ARGB		0
107 
108 /* Timing controller */
109 #define	TCON_GCTL		0x000
110 #define	GCTL_TCON_EN		(1 << 31)
111 #define	GCTL_IO_MAP_SEL_TCON1	(1 << 0)
112 #define	TCON_GINT1		0x008
113 #define	GINT1_TCON1_LINENO(n)	(((n) + 2) << 0)
114 #define	TCON0_DCLK		0x044
115 #define	DCLK_EN			0xf0000000
116 #define	TCON1_CTL		0x090
117 #define	TCON1_EN		(1 << 31)
118 #define	INTERLACE_EN		(1 << 20)
119 #define	TCON1_SRC_SEL(src)	((src) << 0)
120 #define	TCON1_SRC_CH1		0
121 #define	TCON1_SRC_CH2		1
122 #define	TCON1_SRC_BLUE		2
123 #define	TCON1_START_DELAY(sd)	((sd) << 4)
124 #define	TCON1_BASIC0		0x094
125 #define	TCON1_BASIC1		0x098
126 #define	TCON1_BASIC2		0x09c
127 #define	TCON1_BASIC3		0x0a0
128 #define	TCON1_BASIC4		0x0a4
129 #define	TCON1_BASIC5		0x0a8
130 #define	BASIC_X(x)		(((x) - 1) << 16)
131 #define	BASIC_Y(y)		(((y) - 1) << 0)
132 #define	BASIC3_HT(ht)		(((ht) - 1) << 16)
133 #define	BASIC3_HBP(hbp)		(((hbp) - 1) << 0)
134 #define	BASIC4_VT(vt)		((vt) << 16)
135 #define	BASIC4_VBP(vbp)		(((vbp) - 1) << 0)
136 #define	BASIC5_HSPW(hspw)	(((hspw) - 1) << 16)
137 #define	BASIC5_VSPW(vspw)	(((vspw) - 1) << 0)
138 #define	TCON1_IO_POL		0x0f0
139 #define	IO_POL_IO2_INV		(1 << 26)
140 #define	IO_POL_PHSYNC		(1 << 25)
141 #define	IO_POL_PVSYNC		(1 << 24)
142 #define	TCON1_IO_TRI		0x0f4
143 #define	IO0_OUTPUT_TRI_EN	(1 << 24)
144 #define	IO1_OUTPUT_TRI_EN	(1 << 25)
145 #define	IO_TRI_MASK		0xffffffff
146 #define	START_DELAY(vbl)	(MIN(32, (vbl)) - 2)
147 #define	VBLANK_LEN(vt, vd, i)	((((vt) << (i)) >> 1) - (vd) - 2)
148 #define	VTOTAL(vt)		((vt) * 2)
149 #define	DIVIDE(x, y)		(((x) + ((y) / 2)) / (y))
150 
151 struct a10fb_softc {
152 	device_t		dev;
153 	device_t		fbdev;
154 	struct resource		*res[2];
155 
156 	/* Framebuffer */
157 	struct fb_info		info;
158 	size_t			fbsize;
159 	bus_addr_t		paddr;
160 	vm_offset_t		vaddr;
161 
162 	/* HDMI */
163 	eventhandler_tag	hdmi_evh;
164 };
165 
166 static struct resource_spec a10fb_spec[] = {
167 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* DEBE */
168 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* TCON */
169 	{ -1, 0 }
170 };
171 
172 #define	DEBE_READ(sc, reg)		bus_read_4((sc)->res[0], (reg))
173 #define	DEBE_WRITE(sc, reg, val)	bus_write_4((sc)->res[0], (reg), (val))
174 
175 #define	TCON_READ(sc, reg)		bus_read_4((sc)->res[1], (reg))
176 #define	TCON_WRITE(sc, reg, val)	bus_write_4((sc)->res[1], (reg), (val))
177 
178 static int
a10fb_allocfb(struct a10fb_softc * sc)179 a10fb_allocfb(struct a10fb_softc *sc)
180 {
181 	sc->vaddr = kmem_alloc_contig(sc->fbsize, M_NOWAIT | M_ZERO, 0, ~0,
182 	    FB_ALIGN, 0, VM_MEMATTR_WRITE_COMBINING);
183 	if (sc->vaddr == 0) {
184 		device_printf(sc->dev, "failed to allocate FB memory\n");
185 		return (ENOMEM);
186 	}
187 	sc->paddr = pmap_kextract(sc->vaddr);
188 
189 	return (0);
190 }
191 
192 static void
a10fb_freefb(struct a10fb_softc * sc)193 a10fb_freefb(struct a10fb_softc *sc)
194 {
195 	kmem_free(sc->vaddr, sc->fbsize);
196 }
197 
198 static int
a10fb_setup_debe(struct a10fb_softc * sc,const struct videomode * mode)199 a10fb_setup_debe(struct a10fb_softc *sc, const struct videomode *mode)
200 {
201 	int width, height, interlace, reg;
202 	clk_t clk_ahb, clk_dram, clk_debe;
203 	hwreset_t rst;
204 	uint32_t val;
205 	int error;
206 
207 	interlace = !!(mode->flags & VID_INTERLACE);
208 	width = mode->hdisplay;
209 	height = mode->vdisplay << interlace;
210 
211 	/* Leave reset */
212 	error = hwreset_get_by_ofw_name(sc->dev, 0, "de_be", &rst);
213 	if (error != 0) {
214 		device_printf(sc->dev, "cannot find reset 'de_be'\n");
215 		return (error);
216 	}
217 	error = hwreset_deassert(rst);
218 	if (error != 0) {
219 		device_printf(sc->dev, "couldn't de-assert reset 'de_be'\n");
220 		return (error);
221 	}
222 	/* Gating AHB clock for BE */
223 	error = clk_get_by_ofw_name(sc->dev, 0, "ahb_de_be", &clk_ahb);
224 	if (error != 0) {
225 		device_printf(sc->dev, "cannot find clk 'ahb_de_be'\n");
226 		return (error);
227 	}
228 	error = clk_enable(clk_ahb);
229 	if (error != 0) {
230 		device_printf(sc->dev, "cannot enable clk 'ahb_de_be'\n");
231 		return (error);
232 	}
233 	/* Enable DRAM clock to BE */
234 	error = clk_get_by_ofw_name(sc->dev, 0, "dram_de_be", &clk_dram);
235 	if (error != 0) {
236 		device_printf(sc->dev, "cannot find clk 'dram_de_be'\n");
237 		return (error);
238 	}
239 	error = clk_enable(clk_dram);
240 	if (error != 0) {
241 		device_printf(sc->dev, "cannot enable clk 'dram_de_be'\n");
242 		return (error);
243 	}
244 	/* Set BE clock to 300MHz and enable */
245 	error = clk_get_by_ofw_name(sc->dev, 0, "de_be", &clk_debe);
246 	if (error != 0) {
247 		device_printf(sc->dev, "cannot find clk 'de_be'\n");
248 		return (error);
249 	}
250 	error = clk_set_freq(clk_debe, DEBE_FREQ, CLK_SET_ROUND_DOWN);
251 	if (error != 0) {
252 		device_printf(sc->dev, "cannot set 'de_be' frequency\n");
253 		return (error);
254 	}
255 	error = clk_enable(clk_debe);
256 	if (error != 0) {
257 		device_printf(sc->dev, "cannot enable clk 'de_be'\n");
258 		return (error);
259 	}
260 
261 	/* Initialize all registers to 0 */
262 	for (reg = DEBE_REG_START; reg < DEBE_REG_END; reg += DEBE_REG_WIDTH)
263 		DEBE_WRITE(sc, reg, 0);
264 
265 	/* Enable display backend */
266 	DEBE_WRITE(sc, DEBE_MODCTL, MODCTL_EN);
267 
268 	/* Set display size */
269 	DEBE_WRITE(sc, DEBE_DISSIZE, DIS_HEIGHT(height) | DIS_WIDTH(width));
270 
271 	/* Set layer 0 size, position, and stride */
272 	DEBE_WRITE(sc, DEBE_LAYSIZE0, LAY_HEIGHT(height) | LAY_WIDTH(width));
273 	DEBE_WRITE(sc, DEBE_LAYCOOR0, LAY_XCOOR(0) | LAY_YCOOR(0));
274 	DEBE_WRITE(sc, DEBE_LAYLINEWIDTH0, width * FB_BPP);
275 
276 	/* Point layer 0 to FB memory */
277 	DEBE_WRITE(sc, DEBE_LAYFB_L32ADD0, LAYFB_L32ADD(sc->paddr));
278 	DEBE_WRITE(sc, DEBE_LAYFB_H4ADD, LAY0FB_H4ADD(sc->paddr));
279 
280 	/* Set backend format and pixel sequence */
281 	DEBE_WRITE(sc, DEBE_ATTCTL1, ATTCTL1_FBFMT(FBFMT_XRGB8888) |
282 	    ATTCTL1_FBPS(FBPS_32BPP_ARGB));
283 
284 	/* Enable layer 0, output to LCD, setup interlace */
285 	val = DEBE_READ(sc, DEBE_MODCTL);
286 	val |= MODCTL_LAY0_EN;
287 	val &= ~MODCTL_OUT_SEL_MASK;
288 	val |= MODCTL_OUT_SEL(OUT_SEL_LCD);
289 	if (interlace)
290 		val |= MODCTL_ITLMOD_EN;
291 	else
292 		val &= ~MODCTL_ITLMOD_EN;
293 	DEBE_WRITE(sc, DEBE_MODCTL, val);
294 
295 	/* Commit settings */
296 	DEBE_WRITE(sc, DEBE_REGBUFFCTL, REGBUFFCTL_LOAD);
297 
298 	/* Start DEBE */
299 	val = DEBE_READ(sc, DEBE_MODCTL);
300 	val |= MODCTL_START_CTL;
301 	DEBE_WRITE(sc, DEBE_MODCTL, val);
302 
303 	return (0);
304 }
305 
306 static int
a10fb_setup_pll(struct a10fb_softc * sc,uint64_t freq)307 a10fb_setup_pll(struct a10fb_softc *sc, uint64_t freq)
308 {
309 	clk_t clk_sclk1, clk_sclk2;
310 	int error;
311 
312 	error = clk_get_by_ofw_name(sc->dev, 0, "lcd_ch1_sclk1", &clk_sclk1);
313 	if (error != 0) {
314 		device_printf(sc->dev, "cannot find clk 'lcd_ch1_sclk1'\n");
315 		return (error);
316 	}
317 	error = clk_get_by_ofw_name(sc->dev, 0, "lcd_ch1_sclk2", &clk_sclk2);
318 	if (error != 0) {
319 		device_printf(sc->dev, "cannot find clk 'lcd_ch1_sclk2'\n");
320 		return (error);
321 	}
322 
323 	error = clk_set_freq(clk_sclk2, freq, 0);
324 	if (error != 0) {
325 		device_printf(sc->dev, "cannot set lcd ch1 frequency\n");
326 		return (error);
327 	}
328 	error = clk_enable(clk_sclk2);
329 	if (error != 0) {
330 		device_printf(sc->dev, "cannot enable lcd ch1 sclk2\n");
331 		return (error);
332 	}
333 	error = clk_enable(clk_sclk1);
334 	if (error != 0) {
335 		device_printf(sc->dev, "cannot enable lcd ch1 sclk1\n");
336 		return (error);
337 	}
338 
339 	return (0);
340 }
341 
342 static int
a10fb_setup_tcon(struct a10fb_softc * sc,const struct videomode * mode)343 a10fb_setup_tcon(struct a10fb_softc *sc, const struct videomode *mode)
344 {
345 	u_int interlace, hspw, hbp, vspw, vbp, vbl, width, height, start_delay;
346 	u_int vtotal, framerate, clk;
347 	clk_t clk_ahb;
348 	hwreset_t rst;
349 	uint32_t val;
350 	int error;
351 
352 	interlace = !!(mode->flags & VID_INTERLACE);
353 	width = mode->hdisplay;
354 	height = mode->vdisplay;
355 	hspw = mode->hsync_end - mode->hsync_start;
356 	hbp = mode->htotal - mode->hsync_start;
357 	vspw = mode->vsync_end - mode->vsync_start;
358 	vbp = mode->vtotal - mode->vsync_start;
359 	vbl = VBLANK_LEN(mode->vtotal, mode->vdisplay, interlace);
360 	start_delay = START_DELAY(vbl);
361 
362 	/* Leave reset */
363 	error = hwreset_get_by_ofw_name(sc->dev, 0, "lcd", &rst);
364 	if (error != 0) {
365 		device_printf(sc->dev, "cannot find reset 'lcd'\n");
366 		return (error);
367 	}
368 	error = hwreset_deassert(rst);
369 	if (error != 0) {
370 		device_printf(sc->dev, "couldn't de-assert reset 'lcd'\n");
371 		return (error);
372 	}
373 	/* Gating AHB clock for LCD */
374 	error = clk_get_by_ofw_name(sc->dev, 0, "ahb_lcd", &clk_ahb);
375 	if (error != 0) {
376 		device_printf(sc->dev, "cannot find clk 'ahb_lcd'\n");
377 		return (error);
378 	}
379 	error = clk_enable(clk_ahb);
380 	if (error != 0) {
381 		device_printf(sc->dev, "cannot enable clk 'ahb_lcd'\n");
382 		return (error);
383 	}
384 
385 	/* Disable TCON and TCON1 */
386 	TCON_WRITE(sc, TCON_GCTL, 0);
387 	TCON_WRITE(sc, TCON1_CTL, 0);
388 
389 	/* Enable clocks */
390 	TCON_WRITE(sc, TCON0_DCLK, DCLK_EN);
391 
392 	/* Disable IO and data output ports */
393 	TCON_WRITE(sc, TCON1_IO_TRI, IO_TRI_MASK);
394 
395 	/* Disable TCON and select TCON1 */
396 	TCON_WRITE(sc, TCON_GCTL, GCTL_IO_MAP_SEL_TCON1);
397 
398 	/* Source width and height */
399 	TCON_WRITE(sc, TCON1_BASIC0, BASIC_X(width) | BASIC_Y(height));
400 	/* Scaler width and height */
401 	TCON_WRITE(sc, TCON1_BASIC1, BASIC_X(width) | BASIC_Y(height));
402 	/* Output width and height */
403 	TCON_WRITE(sc, TCON1_BASIC2, BASIC_X(width) | BASIC_Y(height));
404 	/* Horizontal total and back porch */
405 	TCON_WRITE(sc, TCON1_BASIC3, BASIC3_HT(mode->htotal) | BASIC3_HBP(hbp));
406 	/* Vertical total and back porch */
407 	vtotal = VTOTAL(mode->vtotal);
408 	if (interlace) {
409 		framerate = DIVIDE(DIVIDE(DOT_CLOCK_TO_HZ(mode->dot_clock),
410 		    mode->htotal), mode->vtotal);
411 		clk = mode->htotal * (VTOTAL(mode->vtotal) + 1) * framerate;
412 		if ((clk / 2) == DOT_CLOCK_TO_HZ(mode->dot_clock))
413 			vtotal += 1;
414 	}
415 	TCON_WRITE(sc, TCON1_BASIC4, BASIC4_VT(vtotal) | BASIC4_VBP(vbp));
416 	/* Horizontal and vertical sync */
417 	TCON_WRITE(sc, TCON1_BASIC5, BASIC5_HSPW(hspw) | BASIC5_VSPW(vspw));
418 	/* Polarity */
419 	val = IO_POL_IO2_INV;
420 	if (mode->flags & VID_PHSYNC)
421 		val |= IO_POL_PHSYNC;
422 	if (mode->flags & VID_PVSYNC)
423 		val |= IO_POL_PVSYNC;
424 	TCON_WRITE(sc, TCON1_IO_POL, val);
425 
426 	/* Set scan line for TCON1 line trigger */
427 	TCON_WRITE(sc, TCON_GINT1, GINT1_TCON1_LINENO(start_delay));
428 
429 	/* Enable TCON1 */
430 	val = TCON1_EN;
431 	if (interlace)
432 		val |= INTERLACE_EN;
433 	val |= TCON1_START_DELAY(start_delay);
434 	val |= TCON1_SRC_SEL(TCON1_SRC_CH1);
435 	TCON_WRITE(sc, TCON1_CTL, val);
436 
437 	/* Setup PLL */
438 	return (a10fb_setup_pll(sc, DOT_CLOCK_TO_HZ(mode->dot_clock)));
439 }
440 
441 static void
a10fb_enable_tcon(struct a10fb_softc * sc,int onoff)442 a10fb_enable_tcon(struct a10fb_softc *sc, int onoff)
443 {
444 	uint32_t val;
445 
446 	/* Enable TCON */
447 	val = TCON_READ(sc, TCON_GCTL);
448 	if (onoff)
449 		val |= GCTL_TCON_EN;
450 	else
451 		val &= ~GCTL_TCON_EN;
452 	TCON_WRITE(sc, TCON_GCTL, val);
453 
454 	/* Enable TCON1 IO0/IO1 outputs */
455 	val = TCON_READ(sc, TCON1_IO_TRI);
456 	if (onoff)
457 		val &= ~(IO0_OUTPUT_TRI_EN | IO1_OUTPUT_TRI_EN);
458 	else
459 		val |= (IO0_OUTPUT_TRI_EN | IO1_OUTPUT_TRI_EN);
460 	TCON_WRITE(sc, TCON1_IO_TRI, val);
461 }
462 
463 static int
a10fb_configure(struct a10fb_softc * sc,const struct videomode * mode)464 a10fb_configure(struct a10fb_softc *sc, const struct videomode *mode)
465 {
466 	size_t fbsize;
467 	int error;
468 
469 	fbsize = round_page(mode->hdisplay * mode->vdisplay * (FB_BPP / NBBY));
470 
471 	/* Detach the old FB device */
472 	if (sc->fbdev != NULL) {
473 		device_delete_child(sc->dev, sc->fbdev);
474 		sc->fbdev = NULL;
475 	}
476 
477 	/* If the FB size has changed, free the old FB memory */
478 	if (sc->fbsize > 0 && sc->fbsize != fbsize) {
479 		a10fb_freefb(sc);
480 		sc->vaddr = 0;
481 	}
482 
483 	/* Allocate the FB if necessary */
484 	sc->fbsize = fbsize;
485 	if (sc->vaddr == 0) {
486 		error = a10fb_allocfb(sc);
487 		if (error != 0) {
488 			device_printf(sc->dev, "failed to allocate FB memory\n");
489 			return (ENXIO);
490 		}
491 	}
492 
493 	/* Setup display backend */
494 	error = a10fb_setup_debe(sc, mode);
495 	if (error != 0)
496 		return (error);
497 
498 	/* Setup display timing controller */
499 	error = a10fb_setup_tcon(sc, mode);
500 	if (error != 0)
501 		return (error);
502 
503 	/* Attach framebuffer device */
504 	sc->info.fb_name = device_get_nameunit(sc->dev);
505 	sc->info.fb_vbase = (intptr_t)sc->vaddr;
506 	sc->info.fb_pbase = sc->paddr;
507 	sc->info.fb_size = sc->fbsize;
508 	sc->info.fb_bpp = sc->info.fb_depth = FB_BPP;
509 	sc->info.fb_stride = mode->hdisplay * (FB_BPP / NBBY);
510 	sc->info.fb_width = mode->hdisplay;
511 	sc->info.fb_height = mode->vdisplay;
512 
513 	sc->fbdev = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
514 	if (sc->fbdev == NULL) {
515 		device_printf(sc->dev, "failed to add fbd child\n");
516 		return (ENOENT);
517 	}
518 
519 	error = device_probe_and_attach(sc->fbdev);
520 	if (error != 0) {
521 		device_printf(sc->dev, "failed to attach fbd device\n");
522 		return (error);
523 	}
524 
525 	return (0);
526 }
527 
528 static void
a10fb_hdmi_event(void * arg,device_t hdmi_dev)529 a10fb_hdmi_event(void *arg, device_t hdmi_dev)
530 {
531 	const struct videomode *mode;
532 	struct videomode hdmi_mode;
533 	struct a10fb_softc *sc;
534 	struct edid_info ei;
535 	uint8_t *edid;
536 	uint32_t edid_len;
537 	int error;
538 
539 	sc = arg;
540 	edid = NULL;
541 	edid_len = 0;
542 	mode = NULL;
543 
544 	error = HDMI_GET_EDID(hdmi_dev, &edid, &edid_len);
545 	if (error != 0) {
546 		device_printf(sc->dev, "failed to get EDID: %d\n", error);
547 	} else {
548 		error = edid_parse(edid, &ei);
549 		if (error != 0) {
550 			device_printf(sc->dev, "failed to parse EDID: %d\n",
551 			    error);
552 		} else {
553 			if (bootverbose)
554 				edid_print(&ei);
555 			mode = ei.edid_preferred_mode;
556 		}
557 	}
558 
559 	/* If the preferred mode could not be determined, use the default */
560 	if (mode == NULL)
561 		mode = pick_mode_by_ref(FB_DEFAULT_W, FB_DEFAULT_H,
562 		    FB_DEFAULT_REF);
563 
564 	if (mode == NULL) {
565 		device_printf(sc->dev, "failed to find usable video mode\n");
566 		return;
567 	}
568 
569 	if (bootverbose)
570 		device_printf(sc->dev, "using %dx%d\n",
571 		    mode->hdisplay, mode->vdisplay);
572 
573 	/* Disable HDMI */
574 	HDMI_ENABLE(hdmi_dev, 0);
575 
576 	/* Disable timing controller */
577 	a10fb_enable_tcon(sc, 0);
578 
579 	/* Configure DEBE and TCON */
580 	error = a10fb_configure(sc, mode);
581 	if (error != 0) {
582 		device_printf(sc->dev, "failed to configure FB: %d\n", error);
583 		return;
584 	}
585 
586 	hdmi_mode = *mode;
587 	hdmi_mode.hskew = mode->hsync_end - mode->hsync_start;
588 	hdmi_mode.flags |= VID_HSKEW;
589 	HDMI_SET_VIDEOMODE(hdmi_dev, &hdmi_mode);
590 
591 	/* Enable timing controller */
592 	a10fb_enable_tcon(sc, 1);
593 
594 	DELAY(HDMI_ENABLE_DELAY);
595 
596 	/* Enable HDMI */
597 	HDMI_ENABLE(hdmi_dev, 1);
598 }
599 
600 static int
a10fb_probe(device_t dev)601 a10fb_probe(device_t dev)
602 {
603 	if (!ofw_bus_status_okay(dev))
604 		return (ENXIO);
605 
606 	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-fb"))
607 		return (ENXIO);
608 
609 	device_set_desc(dev, "Allwinner Framebuffer");
610 	return (BUS_PROBE_DEFAULT);
611 }
612 
613 static int
a10fb_attach(device_t dev)614 a10fb_attach(device_t dev)
615 {
616 	struct a10fb_softc *sc;
617 
618 	sc = device_get_softc(dev);
619 
620 	sc->dev = dev;
621 
622 	if (bus_alloc_resources(dev, a10fb_spec, sc->res)) {
623 		device_printf(dev, "cannot allocate resources for device\n");
624 		return (ENXIO);
625 	}
626 
627 	sc->hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event,
628 	    a10fb_hdmi_event, sc, 0);
629 
630 	return (0);
631 }
632 
633 static struct fb_info *
a10fb_fb_getinfo(device_t dev)634 a10fb_fb_getinfo(device_t dev)
635 {
636 	struct a10fb_softc *sc;
637 
638 	sc = device_get_softc(dev);
639 
640 	return (&sc->info);
641 }
642 
643 static device_method_t a10fb_methods[] = {
644 	/* Device interface */
645 	DEVMETHOD(device_probe,		a10fb_probe),
646 	DEVMETHOD(device_attach,	a10fb_attach),
647 
648 	/* FB interface */
649 	DEVMETHOD(fb_getinfo,		a10fb_fb_getinfo),
650 
651 	DEVMETHOD_END
652 };
653 
654 static driver_t a10fb_driver = {
655 	"fb",
656 	a10fb_methods,
657 	sizeof(struct a10fb_softc),
658 };
659 
660 static devclass_t a10fb_devclass;
661 
662 DRIVER_MODULE(fb, simplebus, a10fb_driver, a10fb_devclass, 0, 0);
663