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 * Ingenic JZ4780 LCD Controller
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/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
59#include <mips/ingenic/jz4780_lcd.h>
60
61#include "fb_if.h"
62#include "hdmi_if.h"
63
64#define	FB_DEFAULT_W	800
65#define	FB_DEFAULT_H	600
66#define	FB_DEFAULT_REF	60
67#define	FB_BPP		32
68#define	FB_ALIGN	(16 * 4)
69#define	FB_MAX_BW	(1920 * 1080 * 60)
70#define	FB_MAX_W	2048
71#define	FB_MAX_H	2048
72#define FB_DIVIDE(x, y)	(((x) + ((y) / 2)) / (y))
73
74#define	PCFG_MAGIC	0xc7ff2100
75
76#define	DOT_CLOCK_TO_HZ(c)	((c) * 1000)
77
78#ifndef VM_MEMATTR_WRITE_COMBINING
79#define	VM_MEMATTR_WRITE_COMBINING VM_MEMATTR_UNCACHEABLE
80#endif
81
82struct jzlcd_softc {
83	device_t		dev;
84	device_t		fbdev;
85	struct resource		*res[1];
86
87	/* Clocks */
88	clk_t			clk;
89	clk_t			clk_pix;
90
91	/* Framebuffer */
92	struct fb_info		info;
93	size_t			fbsize;
94	bus_addr_t		paddr;
95	vm_offset_t		vaddr;
96
97	/* HDMI */
98	eventhandler_tag	hdmi_evh;
99
100	/* Frame descriptor DMA */
101	bus_dma_tag_t		fdesc_tag;
102	bus_dmamap_t		fdesc_map;
103	bus_addr_t		fdesc_paddr;
104	struct lcd_frame_descriptor	*fdesc;
105};
106
107static struct resource_spec jzlcd_spec[] = {
108	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
109	{ -1, 0 }
110};
111
112#define	LCD_READ(sc, reg)		bus_read_4((sc)->res[0], (reg))
113#define	LCD_WRITE(sc, reg, val)		bus_write_4((sc)->res[0], (reg), (val))
114
115static int
116jzlcd_allocfb(struct jzlcd_softc *sc)
117{
118	sc->vaddr = kmem_alloc_contig(sc->fbsize, M_NOWAIT | M_ZERO, 0, ~0,
119	    FB_ALIGN, 0, VM_MEMATTR_WRITE_COMBINING);
120	if (sc->vaddr == 0) {
121		device_printf(sc->dev, "failed to allocate FB memory\n");
122		return (ENOMEM);
123	}
124	sc->paddr = pmap_kextract(sc->vaddr);
125
126	return (0);
127}
128
129static void
130jzlcd_freefb(struct jzlcd_softc *sc)
131{
132	kmem_free(sc->vaddr, sc->fbsize);
133}
134
135static void
136jzlcd_start(struct jzlcd_softc *sc)
137{
138	uint32_t ctrl;
139
140	/* Clear status registers */
141	LCD_WRITE(sc, LCDSTATE, 0);
142	LCD_WRITE(sc, LCDOSDS, 0);
143	/* Enable the controller */
144	ctrl = LCD_READ(sc, LCDCTRL);
145	ctrl |= LCDCTRL_ENA;
146	ctrl &= ~LCDCTRL_DIS;
147	LCD_WRITE(sc, LCDCTRL, ctrl);
148}
149
150static void
151jzlcd_stop(struct jzlcd_softc *sc)
152{
153	uint32_t ctrl;
154
155	ctrl = LCD_READ(sc, LCDCTRL);
156	if ((ctrl & LCDCTRL_ENA) != 0) {
157		/* Disable the controller and wait for it to stop */
158		ctrl |= LCDCTRL_DIS;
159		LCD_WRITE(sc, LCDCTRL, ctrl);
160		while ((LCD_READ(sc, LCDSTATE) & LCDSTATE_LDD) == 0)
161			DELAY(100);
162	}
163	/* Clear all status except for disable */
164	LCD_WRITE(sc, LCDSTATE, LCD_READ(sc, LCDSTATE) & ~LCDSTATE_LDD);
165}
166
167static void
168jzlcd_setup_descriptor(struct jzlcd_softc *sc, const struct videomode *mode,
169    u_int desno)
170{
171	struct lcd_frame_descriptor *fdesc;
172	int line_sz;
173
174	/* Frame size is specified in # words */
175	line_sz = (mode->hdisplay * FB_BPP) >> 3;
176	line_sz = ((line_sz + 3) & ~3) / 4;
177
178	fdesc = sc->fdesc + desno;
179
180	if (desno == 0)
181		fdesc->next = sc->fdesc_paddr +
182		    sizeof(struct lcd_frame_descriptor);
183	else
184		fdesc->next = sc->fdesc_paddr;
185	fdesc->physaddr = sc->paddr;
186	fdesc->id = desno;
187	fdesc->cmd = LCDCMD_FRM_EN | (line_sz * mode->vdisplay);
188	fdesc->offs = 0;
189	fdesc->pw = 0;
190	fdesc->cnum_pos = LCDPOS_BPP01_18_24 |
191	    LCDPOS_PREMULTI01 |
192	    (desno == 0 ? LCDPOS_COEF_BLE01_1 : LCDPOS_COEF_SLE01);
193	fdesc->dessize = LCDDESSIZE_ALPHA |
194	    ((mode->vdisplay - 1) << LCDDESSIZE_HEIGHT_SHIFT) |
195	    ((mode->hdisplay - 1) << LCDDESSIZE_WIDTH_SHIFT);
196}
197
198static int
199jzlcd_set_videomode(struct jzlcd_softc *sc, const struct videomode *mode)
200{
201	u_int hbp, hfp, hsw, vbp, vfp, vsw;
202	u_int hds, hde, ht, vds, vde, vt;
203	uint32_t ctrl;
204	int error;
205
206	hbp = mode->htotal - mode->hsync_end;
207	hfp = mode->hsync_start - mode->hdisplay;
208	hsw = mode->hsync_end - mode->hsync_start;
209	vbp = mode->vtotal - mode->vsync_end;
210	vfp = mode->vsync_start - mode->vdisplay;
211	vsw = mode->vsync_end - mode->vsync_start;
212
213	hds = hsw + hbp;
214	hde = hds + mode->hdisplay;
215	ht = hde + hfp;
216
217	vds = vsw + vbp;
218	vde = vds + mode->vdisplay;
219	vt = vde + vfp;
220
221	/* Setup timings */
222	LCD_WRITE(sc, LCDVAT,
223	    (ht << LCDVAT_HT_SHIFT) | (vt << LCDVAT_VT_SHIFT));
224	LCD_WRITE(sc, LCDDAH,
225	    (hds << LCDDAH_HDS_SHIFT) | (hde << LCDDAH_HDE_SHIFT));
226	LCD_WRITE(sc, LCDDAV,
227	    (vds << LCDDAV_VDS_SHIFT) | (vde << LCDDAV_VDE_SHIFT));
228	LCD_WRITE(sc, LCDHSYNC, hsw);
229	LCD_WRITE(sc, LCDVSYNC, vsw);
230
231	/* Set configuration */
232	LCD_WRITE(sc, LCDCFG, LCDCFG_NEWDES | LCDCFG_RECOVER | LCDCFG_24 |
233	    LCDCFG_PSM | LCDCFG_CLSM | LCDCFG_SPLM | LCDCFG_REVM | LCDCFG_PCP);
234	ctrl = LCD_READ(sc, LCDCTRL);
235	ctrl &= ~LCDCTRL_BST;
236	ctrl |= LCDCTRL_BST_64 | LCDCTRL_OFUM;
237	LCD_WRITE(sc, LCDCTRL, ctrl);
238	LCD_WRITE(sc, LCDPCFG, PCFG_MAGIC);
239	LCD_WRITE(sc, LCDRGBC, LCDRGBC_RGBFMT);
240
241	/* Update registers */
242	LCD_WRITE(sc, LCDSTATE, 0);
243
244	/* Setup frame descriptors */
245	jzlcd_setup_descriptor(sc, mode, 0);
246	jzlcd_setup_descriptor(sc, mode, 1);
247	bus_dmamap_sync(sc->fdesc_tag, sc->fdesc_map, BUS_DMASYNC_PREWRITE);
248
249	/* Setup DMA channels */
250	LCD_WRITE(sc, LCDDA0, sc->fdesc_paddr
251	    + sizeof(struct lcd_frame_descriptor));
252	LCD_WRITE(sc, LCDDA1, sc->fdesc_paddr);
253
254	/* Set display clock */
255	error = clk_set_freq(sc->clk_pix, DOT_CLOCK_TO_HZ(mode->dot_clock), 0);
256	if (error != 0) {
257		device_printf(sc->dev, "failed to set pixel clock to %u Hz\n",
258		    DOT_CLOCK_TO_HZ(mode->dot_clock));
259		return (error);
260	}
261
262	return (0);
263}
264
265static int
266jzlcd_configure(struct jzlcd_softc *sc, const struct videomode *mode)
267{
268	size_t fbsize;
269	int error;
270
271	fbsize = round_page(mode->hdisplay * mode->vdisplay * (FB_BPP / NBBY));
272
273	/* Detach the old FB device */
274	if (sc->fbdev != NULL) {
275		device_delete_child(sc->dev, sc->fbdev);
276		sc->fbdev = NULL;
277	}
278
279	/* If the FB size has changed, free the old FB memory */
280	if (sc->fbsize > 0 && sc->fbsize != fbsize) {
281		jzlcd_freefb(sc);
282		sc->vaddr = 0;
283	}
284
285	/* Allocate the FB if necessary */
286	sc->fbsize = fbsize;
287	if (sc->vaddr == 0) {
288		error = jzlcd_allocfb(sc);
289		if (error != 0) {
290			device_printf(sc->dev, "failed to allocate FB memory\n");
291			return (ENXIO);
292		}
293	}
294
295	/* Setup video mode */
296	error = jzlcd_set_videomode(sc, mode);
297	if (error != 0)
298		return (error);
299
300	/* Attach framebuffer device */
301	sc->info.fb_name = device_get_nameunit(sc->dev);
302	sc->info.fb_vbase = (intptr_t)sc->vaddr;
303	sc->info.fb_pbase = sc->paddr;
304	sc->info.fb_size = sc->fbsize;
305	sc->info.fb_bpp = sc->info.fb_depth = FB_BPP;
306	sc->info.fb_stride = mode->hdisplay * (FB_BPP / NBBY);
307	sc->info.fb_width = mode->hdisplay;
308	sc->info.fb_height = mode->vdisplay;
309#ifdef VM_MEMATTR_WRITE_COMBINING
310	sc->info.fb_flags = FB_FLAG_MEMATTR;
311	sc->info.fb_memattr = VM_MEMATTR_WRITE_COMBINING;
312#endif
313	sc->fbdev = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
314	if (sc->fbdev == NULL) {
315		device_printf(sc->dev, "failed to add fbd child\n");
316		return (ENOENT);
317	}
318
319	error = device_probe_and_attach(sc->fbdev);
320	if (error != 0) {
321		device_printf(sc->dev, "failed to attach fbd device\n");
322		return (error);
323	}
324
325	return (0);
326}
327
328static int
329jzlcd_get_bandwidth(const struct videomode *mode)
330{
331	int refresh;
332
333	refresh = FB_DIVIDE(FB_DIVIDE(DOT_CLOCK_TO_HZ(mode->dot_clock),
334	    mode->htotal), mode->vtotal);
335
336	return mode->hdisplay * mode->vdisplay * refresh;
337}
338
339static int
340jzlcd_mode_supported(const struct videomode *mode)
341{
342	/* Width and height must be less than 2048 */
343	if (mode->hdisplay > FB_MAX_W || mode->vdisplay > FB_MAX_H)
344		return (0);
345
346	/* Bandwidth check */
347	if (jzlcd_get_bandwidth(mode) > FB_MAX_BW)
348		return (0);
349
350	/* Interlace modes not yet supported by the driver */
351	if ((mode->flags & VID_INTERLACE) != 0)
352		return (0);
353
354	return (1);
355}
356
357static const struct videomode *
358jzlcd_find_mode(struct edid_info *ei)
359{
360	const struct videomode *best;
361	int n, bw, best_bw;
362
363	/* If the preferred mode is OK, just use it */
364	if (jzlcd_mode_supported(ei->edid_preferred_mode) != 0)
365		return ei->edid_preferred_mode;
366
367	/* Pick the mode with the highest bandwidth requirements */
368	best = NULL;
369	best_bw = 0;
370	for (n = 0; n < ei->edid_nmodes; n++) {
371		if (jzlcd_mode_supported(&ei->edid_modes[n]) == 0)
372			continue;
373		bw = jzlcd_get_bandwidth(&ei->edid_modes[n]);
374		if (bw > FB_MAX_BW)
375			continue;
376		if (best == NULL || bw > best_bw) {
377			best = &ei->edid_modes[n];
378			best_bw = bw;
379		}
380	}
381
382	return best;
383}
384
385static void
386jzlcd_hdmi_event(void *arg, device_t hdmi_dev)
387{
388	const struct videomode *mode;
389	struct videomode hdmi_mode;
390	struct jzlcd_softc *sc;
391	struct edid_info ei;
392	uint8_t *edid;
393	uint32_t edid_len;
394	int error;
395
396	sc = arg;
397	edid = NULL;
398	edid_len = 0;
399	mode = NULL;
400
401	error = HDMI_GET_EDID(hdmi_dev, &edid, &edid_len);
402	if (error != 0) {
403		device_printf(sc->dev, "failed to get EDID: %d\n", error);
404	} else {
405		error = edid_parse(edid, &ei);
406		if (error != 0) {
407			device_printf(sc->dev, "failed to parse EDID: %d\n",
408			    error);
409		} else {
410			if (bootverbose)
411				edid_print(&ei);
412
413			mode = jzlcd_find_mode(&ei);
414		}
415	}
416
417	/* If a suitable mode could not be found, try the default */
418	if (mode == NULL)
419		mode = pick_mode_by_ref(FB_DEFAULT_W, FB_DEFAULT_H,
420		    FB_DEFAULT_REF);
421
422	if (mode == NULL) {
423		device_printf(sc->dev, "failed to find usable video mode\n");
424		return;
425	}
426
427	if (bootverbose)
428		device_printf(sc->dev, "using %dx%d\n",
429		    mode->hdisplay, mode->vdisplay);
430
431	/* Stop the controller */
432	jzlcd_stop(sc);
433
434	/* Configure LCD controller */
435	error = jzlcd_configure(sc, mode);
436	if (error != 0) {
437		device_printf(sc->dev, "failed to configure FB: %d\n", error);
438		return;
439	}
440
441	/* Enable HDMI TX */
442	hdmi_mode = *mode;
443	HDMI_SET_VIDEOMODE(hdmi_dev, &hdmi_mode);
444
445	/* Start the controller! */
446	jzlcd_start(sc);
447}
448
449static void
450jzlcd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
451{
452	if (error != 0)
453		return;
454	*(bus_addr_t *)arg = segs[0].ds_addr;
455}
456
457static int
458jzlcd_probe(device_t dev)
459{
460	if (!ofw_bus_status_okay(dev))
461		return (ENXIO);
462
463	if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-lcd"))
464		return (ENXIO);
465
466	device_set_desc(dev, "Ingenic JZ4780 LCD Controller");
467	return (BUS_PROBE_DEFAULT);
468}
469
470static int
471jzlcd_attach(device_t dev)
472{
473	struct jzlcd_softc *sc;
474	int error;
475
476	sc = device_get_softc(dev);
477
478	sc->dev = dev;
479
480	if (bus_alloc_resources(dev, jzlcd_spec, sc->res)) {
481		device_printf(dev, "cannot allocate resources for device\n");
482		goto failed;
483	}
484
485	if (clk_get_by_ofw_name(dev, 0, "lcd_clk", &sc->clk) != 0 ||
486	    clk_get_by_ofw_name(dev, 0, "lcd_pixclk", &sc->clk_pix) != 0) {
487		device_printf(dev, "cannot get clocks\n");
488		goto failed;
489	}
490	if (clk_enable(sc->clk) != 0 || clk_enable(sc->clk_pix) != 0) {
491		device_printf(dev, "cannot enable clocks\n");
492		goto failed;
493	}
494
495	error = bus_dma_tag_create(
496	    bus_get_dma_tag(dev),
497	    sizeof(struct lcd_frame_descriptor), 0,
498	    BUS_SPACE_MAXADDR_32BIT,
499	    BUS_SPACE_MAXADDR,
500	    NULL, NULL,
501	    sizeof(struct lcd_frame_descriptor) * 2, 1,
502	    sizeof(struct lcd_frame_descriptor) * 2,
503	    0,
504	    NULL, NULL,
505	    &sc->fdesc_tag);
506	if (error != 0) {
507		device_printf(dev, "cannot create bus dma tag\n");
508		goto failed;
509	}
510
511	error = bus_dmamem_alloc(sc->fdesc_tag, (void **)&sc->fdesc,
512	    BUS_DMA_NOCACHE | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->fdesc_map);
513	if (error != 0) {
514		device_printf(dev, "cannot allocate dma descriptor\n");
515		goto dmaalloc_failed;
516	}
517
518	error = bus_dmamap_load(sc->fdesc_tag, sc->fdesc_map, sc->fdesc,
519	    sizeof(struct lcd_frame_descriptor) * 2, jzlcd_dmamap_cb,
520	    &sc->fdesc_paddr, 0);
521	if (error != 0) {
522		device_printf(dev, "cannot load dma map\n");
523		goto dmaload_failed;
524	}
525
526	sc->hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event,
527	    jzlcd_hdmi_event, sc, 0);
528
529	return (0);
530
531dmaload_failed:
532	bus_dmamem_free(sc->fdesc_tag, sc->fdesc, sc->fdesc_map);
533dmaalloc_failed:
534	bus_dma_tag_destroy(sc->fdesc_tag);
535failed:
536	if (sc->clk_pix != NULL)
537		clk_release(sc->clk);
538	if (sc->clk != NULL)
539		clk_release(sc->clk);
540	if (sc->res != NULL)
541		bus_release_resources(dev, jzlcd_spec, sc->res);
542
543	return (ENXIO);
544}
545
546static struct fb_info *
547jzlcd_fb_getinfo(device_t dev)
548{
549	struct jzlcd_softc *sc;
550
551	sc = device_get_softc(dev);
552
553	return (&sc->info);
554}
555
556static device_method_t jzlcd_methods[] = {
557	/* Device interface */
558	DEVMETHOD(device_probe,		jzlcd_probe),
559	DEVMETHOD(device_attach,	jzlcd_attach),
560
561	/* FB interface */
562	DEVMETHOD(fb_getinfo,		jzlcd_fb_getinfo),
563
564	DEVMETHOD_END
565};
566
567static driver_t jzlcd_driver = {
568	"fb",
569	jzlcd_methods,
570	sizeof(struct jzlcd_softc),
571};
572
573static devclass_t jzlcd_devclass;
574
575DRIVER_MODULE(fb, simplebus, jzlcd_driver, jzlcd_devclass, 0, 0);
576