2 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
30 * Ingenic JZ4780 LCD Controller
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/eventhandler.h>
41 #include <sys/condvar.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
46 #include <vm/vm_extern.h>
47 #include <vm/vm_kern.h>
50 #include <machine/bus.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
55 #include <dev/videomode/videomode.h>
56 #include <dev/videomode/edidvar.h>
58 #include <dev/extres/clk/clk.h>
60 #include <mips/ingenic/jz4780_lcd.h>
65 #define FB_DEFAULT_W 800
66 #define FB_DEFAULT_H 600
67 #define FB_DEFAULT_REF 60
69 #define FB_ALIGN (16 * 4)
70 #define FB_MAX_BW (1920 * 1080 * 60)
73 #define FB_DIVIDE(x, y) (((x) + ((y) / 2)) / (y))
75 #define PCFG_MAGIC 0xc7ff2100
77 #define DOT_CLOCK_TO_HZ(c) ((c) * 1000)
79 #ifndef VM_MEMATTR_WRITE_COMBINING
80 #define VM_MEMATTR_WRITE_COMBINING VM_MEMATTR_UNCACHEABLE
86 struct resource *res[1];
99 eventhandler_tag hdmi_evh;
101 /* Frame descriptor DMA */
102 bus_dma_tag_t fdesc_tag;
103 bus_dmamap_t fdesc_map;
104 bus_addr_t fdesc_paddr;
105 struct lcd_frame_descriptor *fdesc;
108 static struct resource_spec jzlcd_spec[] = {
109 { SYS_RES_MEMORY, 0, RF_ACTIVE },
113 #define LCD_READ(sc, reg) bus_read_4((sc)->res[0], (reg))
114 #define LCD_WRITE(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val))
117 jzlcd_allocfb(struct jzlcd_softc *sc)
119 sc->vaddr = kmem_alloc_contig(sc->fbsize, M_NOWAIT | M_ZERO, 0, ~0,
120 FB_ALIGN, 0, VM_MEMATTR_WRITE_COMBINING);
121 if (sc->vaddr == 0) {
122 device_printf(sc->dev, "failed to allocate FB memory\n");
125 sc->paddr = pmap_kextract(sc->vaddr);
131 jzlcd_freefb(struct jzlcd_softc *sc)
133 kmem_free(sc->vaddr, sc->fbsize);
137 jzlcd_start(struct jzlcd_softc *sc)
141 /* Clear status registers */
142 LCD_WRITE(sc, LCDSTATE, 0);
143 LCD_WRITE(sc, LCDOSDS, 0);
144 /* Enable the controller */
145 ctrl = LCD_READ(sc, LCDCTRL);
147 ctrl &= ~LCDCTRL_DIS;
148 LCD_WRITE(sc, LCDCTRL, ctrl);
152 jzlcd_stop(struct jzlcd_softc *sc)
156 ctrl = LCD_READ(sc, LCDCTRL);
157 if ((ctrl & LCDCTRL_ENA) != 0) {
158 /* Disable the controller and wait for it to stop */
160 LCD_WRITE(sc, LCDCTRL, ctrl);
161 while ((LCD_READ(sc, LCDSTATE) & LCDSTATE_LDD) == 0)
164 /* Clear all status except for disable */
165 LCD_WRITE(sc, LCDSTATE, LCD_READ(sc, LCDSTATE) & ~LCDSTATE_LDD);
169 jzlcd_setup_descriptor(struct jzlcd_softc *sc, const struct videomode *mode,
172 struct lcd_frame_descriptor *fdesc;
175 /* Frame size is specified in # words */
176 line_sz = (mode->hdisplay * FB_BPP) >> 3;
177 line_sz = ((line_sz + 3) & ~3) / 4;
179 fdesc = sc->fdesc + desno;
182 fdesc->next = sc->fdesc_paddr +
183 sizeof(struct lcd_frame_descriptor);
185 fdesc->next = sc->fdesc_paddr;
186 fdesc->physaddr = sc->paddr;
188 fdesc->cmd = LCDCMD_FRM_EN | (line_sz * mode->vdisplay);
191 fdesc->cnum_pos = LCDPOS_BPP01_18_24 |
193 (desno == 0 ? LCDPOS_COEF_BLE01_1 : LCDPOS_COEF_SLE01);
194 fdesc->dessize = LCDDESSIZE_ALPHA |
195 ((mode->vdisplay - 1) << LCDDESSIZE_HEIGHT_SHIFT) |
196 ((mode->hdisplay - 1) << LCDDESSIZE_WIDTH_SHIFT);
200 jzlcd_set_videomode(struct jzlcd_softc *sc, const struct videomode *mode)
202 u_int hbp, hfp, hsw, vbp, vfp, vsw;
203 u_int hds, hde, ht, vds, vde, vt;
207 hbp = mode->htotal - mode->hsync_end;
208 hfp = mode->hsync_start - mode->hdisplay;
209 hsw = mode->hsync_end - mode->hsync_start;
210 vbp = mode->vtotal - mode->vsync_end;
211 vfp = mode->vsync_start - mode->vdisplay;
212 vsw = mode->vsync_end - mode->vsync_start;
215 hde = hds + mode->hdisplay;
219 vde = vds + mode->vdisplay;
223 LCD_WRITE(sc, LCDVAT,
224 (ht << LCDVAT_HT_SHIFT) | (vt << LCDVAT_VT_SHIFT));
225 LCD_WRITE(sc, LCDDAH,
226 (hds << LCDDAH_HDS_SHIFT) | (hde << LCDDAH_HDE_SHIFT));
227 LCD_WRITE(sc, LCDDAV,
228 (vds << LCDDAV_VDS_SHIFT) | (vde << LCDDAV_VDE_SHIFT));
229 LCD_WRITE(sc, LCDHSYNC, hsw);
230 LCD_WRITE(sc, LCDVSYNC, vsw);
232 /* Set configuration */
233 LCD_WRITE(sc, LCDCFG, LCDCFG_NEWDES | LCDCFG_RECOVER | LCDCFG_24 |
234 LCDCFG_PSM | LCDCFG_CLSM | LCDCFG_SPLM | LCDCFG_REVM | LCDCFG_PCP);
235 ctrl = LCD_READ(sc, LCDCTRL);
236 ctrl &= ~LCDCTRL_BST;
237 ctrl |= LCDCTRL_BST_64 | LCDCTRL_OFUM;
238 LCD_WRITE(sc, LCDCTRL, ctrl);
239 LCD_WRITE(sc, LCDPCFG, PCFG_MAGIC);
240 LCD_WRITE(sc, LCDRGBC, LCDRGBC_RGBFMT);
242 /* Update registers */
243 LCD_WRITE(sc, LCDSTATE, 0);
245 /* Setup frame descriptors */
246 jzlcd_setup_descriptor(sc, mode, 0);
247 jzlcd_setup_descriptor(sc, mode, 1);
248 bus_dmamap_sync(sc->fdesc_tag, sc->fdesc_map, BUS_DMASYNC_PREWRITE);
250 /* Setup DMA channels */
251 LCD_WRITE(sc, LCDDA0, sc->fdesc_paddr
252 + sizeof(struct lcd_frame_descriptor));
253 LCD_WRITE(sc, LCDDA1, sc->fdesc_paddr);
255 /* Set display clock */
256 error = clk_set_freq(sc->clk_pix, DOT_CLOCK_TO_HZ(mode->dot_clock), 0);
258 device_printf(sc->dev, "failed to set pixel clock to %u Hz\n",
259 DOT_CLOCK_TO_HZ(mode->dot_clock));
267 jzlcd_configure(struct jzlcd_softc *sc, const struct videomode *mode)
272 fbsize = round_page(mode->hdisplay * mode->vdisplay * (FB_BPP / NBBY));
274 /* Detach the old FB device */
275 if (sc->fbdev != NULL) {
276 device_delete_child(sc->dev, sc->fbdev);
280 /* If the FB size has changed, free the old FB memory */
281 if (sc->fbsize > 0 && sc->fbsize != fbsize) {
286 /* Allocate the FB if necessary */
288 if (sc->vaddr == 0) {
289 error = jzlcd_allocfb(sc);
291 device_printf(sc->dev, "failed to allocate FB memory\n");
296 /* Setup video mode */
297 error = jzlcd_set_videomode(sc, mode);
301 /* Attach framebuffer device */
302 sc->info.fb_name = device_get_nameunit(sc->dev);
303 sc->info.fb_vbase = (intptr_t)sc->vaddr;
304 sc->info.fb_pbase = sc->paddr;
305 sc->info.fb_size = sc->fbsize;
306 sc->info.fb_bpp = sc->info.fb_depth = FB_BPP;
307 sc->info.fb_stride = mode->hdisplay * (FB_BPP / NBBY);
308 sc->info.fb_width = mode->hdisplay;
309 sc->info.fb_height = mode->vdisplay;
310 #ifdef VM_MEMATTR_WRITE_COMBINING
311 sc->info.fb_flags = FB_FLAG_MEMATTR;
312 sc->info.fb_memattr = VM_MEMATTR_WRITE_COMBINING;
314 sc->fbdev = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
315 if (sc->fbdev == NULL) {
316 device_printf(sc->dev, "failed to add fbd child\n");
320 error = device_probe_and_attach(sc->fbdev);
322 device_printf(sc->dev, "failed to attach fbd device\n");
330 jzlcd_get_bandwidth(const struct videomode *mode)
334 refresh = FB_DIVIDE(FB_DIVIDE(DOT_CLOCK_TO_HZ(mode->dot_clock),
335 mode->htotal), mode->vtotal);
337 return mode->hdisplay * mode->vdisplay * refresh;
341 jzlcd_mode_supported(const struct videomode *mode)
343 /* Width and height must be less than 2048 */
344 if (mode->hdisplay > FB_MAX_W || mode->vdisplay > FB_MAX_H)
347 /* Bandwidth check */
348 if (jzlcd_get_bandwidth(mode) > FB_MAX_BW)
351 /* Interlace modes not yet supported by the driver */
352 if ((mode->flags & VID_INTERLACE) != 0)
358 static const struct videomode *
359 jzlcd_find_mode(struct edid_info *ei)
361 const struct videomode *best;
364 /* If the preferred mode is OK, just use it */
365 if (jzlcd_mode_supported(ei->edid_preferred_mode) != 0)
366 return ei->edid_preferred_mode;
368 /* Pick the mode with the highest bandwidth requirements */
371 for (n = 0; n < ei->edid_nmodes; n++) {
372 if (jzlcd_mode_supported(&ei->edid_modes[n]) == 0)
374 bw = jzlcd_get_bandwidth(&ei->edid_modes[n]);
377 if (best == NULL || bw > best_bw) {
378 best = &ei->edid_modes[n];
387 jzlcd_hdmi_event(void *arg, device_t hdmi_dev)
389 const struct videomode *mode;
390 struct videomode hdmi_mode;
391 struct jzlcd_softc *sc;
402 error = HDMI_GET_EDID(hdmi_dev, &edid, &edid_len);
404 device_printf(sc->dev, "failed to get EDID: %d\n", error);
406 error = edid_parse(edid, &ei);
408 device_printf(sc->dev, "failed to parse EDID: %d\n",
414 mode = jzlcd_find_mode(&ei);
418 /* If a suitable mode could not be found, try the default */
420 mode = pick_mode_by_ref(FB_DEFAULT_W, FB_DEFAULT_H,
424 device_printf(sc->dev, "failed to find usable video mode\n");
429 device_printf(sc->dev, "using %dx%d\n",
430 mode->hdisplay, mode->vdisplay);
432 /* Stop the controller */
435 /* Configure LCD controller */
436 error = jzlcd_configure(sc, mode);
438 device_printf(sc->dev, "failed to configure FB: %d\n", error);
444 HDMI_SET_VIDEOMODE(hdmi_dev, &hdmi_mode);
446 /* Start the controller! */
451 jzlcd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
455 *(bus_addr_t *)arg = segs[0].ds_addr;
459 jzlcd_probe(device_t dev)
461 if (!ofw_bus_status_okay(dev))
464 if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-lcd"))
467 device_set_desc(dev, "Ingenic JZ4780 LCD Controller");
468 return (BUS_PROBE_DEFAULT);
472 jzlcd_attach(device_t dev)
474 struct jzlcd_softc *sc;
477 sc = device_get_softc(dev);
481 if (bus_alloc_resources(dev, jzlcd_spec, sc->res)) {
482 device_printf(dev, "cannot allocate resources for device\n");
486 if (clk_get_by_ofw_name(dev, 0, "lcd_clk", &sc->clk) != 0 ||
487 clk_get_by_ofw_name(dev, 0, "lcd_pixclk", &sc->clk_pix) != 0) {
488 device_printf(dev, "cannot get clocks\n");
491 if (clk_enable(sc->clk) != 0 || clk_enable(sc->clk_pix) != 0) {
492 device_printf(dev, "cannot enable clocks\n");
496 error = bus_dma_tag_create(
497 bus_get_dma_tag(dev),
498 sizeof(struct lcd_frame_descriptor), 0,
499 BUS_SPACE_MAXADDR_32BIT,
502 sizeof(struct lcd_frame_descriptor) * 2, 1,
503 sizeof(struct lcd_frame_descriptor) * 2,
508 device_printf(dev, "cannot create bus dma tag\n");
512 error = bus_dmamem_alloc(sc->fdesc_tag, (void **)&sc->fdesc,
513 BUS_DMA_NOCACHE | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->fdesc_map);
515 device_printf(dev, "cannot allocate dma descriptor\n");
516 goto dmaalloc_failed;
519 error = bus_dmamap_load(sc->fdesc_tag, sc->fdesc_map, sc->fdesc,
520 sizeof(struct lcd_frame_descriptor) * 2, jzlcd_dmamap_cb,
521 &sc->fdesc_paddr, 0);
523 device_printf(dev, "cannot load dma map\n");
527 sc->hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event,
528 jzlcd_hdmi_event, sc, 0);
533 bus_dmamem_free(sc->fdesc_tag, sc->fdesc, sc->fdesc_map);
535 bus_dma_tag_destroy(sc->fdesc_tag);
537 if (sc->clk_pix != NULL)
538 clk_release(sc->clk);
540 clk_release(sc->clk);
542 bus_release_resources(dev, jzlcd_spec, sc->res);
547 static struct fb_info *
548 jzlcd_fb_getinfo(device_t dev)
550 struct jzlcd_softc *sc;
552 sc = device_get_softc(dev);
557 static device_method_t jzlcd_methods[] = {
558 /* Device interface */
559 DEVMETHOD(device_probe, jzlcd_probe),
560 DEVMETHOD(device_attach, jzlcd_attach),
563 DEVMETHOD(fb_getinfo, jzlcd_fb_getinfo),
568 static driver_t jzlcd_driver = {
571 sizeof(struct jzlcd_softc),
574 static devclass_t jzlcd_devclass;
576 DRIVER_MODULE(fb, simplebus, jzlcd_driver, jzlcd_devclass, 0, 0);