svn commit: r310308 - in head/sys/mips: conf ingenic

Jared McNeill jmcneill at FreeBSD.org
Tue Dec 20 01:51:11 UTC 2016


Author: jmcneill
Date: Tue Dec 20 01:51:09 2016
New Revision: 310308
URL: https://svnweb.freebsd.org/changeset/base/310308

Log:
  Add support for Ingenic JZ4780 LCD controller and enable framebuffer
  console support.
  
  Reviewed by:		kan
  Differential Revision:	https://reviews.freebsd.org/D8827

Added:
  head/sys/mips/ingenic/jz4780_lcd.c   (contents, props changed)
  head/sys/mips/ingenic/jz4780_lcd.h   (contents, props changed)
Modified:
  head/sys/mips/conf/JZ4780
  head/sys/mips/ingenic/files.jz4780

Modified: head/sys/mips/conf/JZ4780
==============================================================================
--- head/sys/mips/conf/JZ4780	Tue Dec 20 01:37:00 2016	(r310307)
+++ head/sys/mips/conf/JZ4780	Tue Dec 20 01:51:09 2016	(r310308)
@@ -86,6 +86,16 @@ device		mmcsd
 
 device		dme
 
+device		iic
+device		iicbus
+
+# Framebuffer console support
+device		vt
+device		kbdmux
+device		hdmi
+device		videomode
+device		pty
+
 # USB support
 options 	USB_DEBUG	# enable debug msgs
 options 	USB_HOST_ALIGN=128 # L2 cache line size
@@ -95,6 +105,7 @@ device		dwcotg		# DesignWare HS OTG cont
 device		usb		# USB Bus (required)
 #device		udbp		# USB Double Bulk Pipe devices
 device		uhid		# "Human Interface Devices"
+device		ukbd		# Allow keyboard like HIDs to control console
 #device		ulpt		# Printer
 device		umass		# Disks/Mass storage - Requires scbus and da
 device		ums		# Mouse

Modified: head/sys/mips/ingenic/files.jz4780
==============================================================================
--- head/sys/mips/ingenic/files.jz4780	Tue Dec 20 01:37:00 2016	(r310307)
+++ head/sys/mips/ingenic/files.jz4780	Tue Dec 20 01:51:09 2016	(r310308)
@@ -6,6 +6,9 @@ mips/ingenic/jz4780_mmc.c	optional mmc
 mips/ingenic/jz4780_ohci.c	optional ohci
 mips/ingenic/jz4780_smb.c	optional iicbus
 mips/ingenic/jz4780_uart.c	optional uart
+mips/ingenic/jz4780_lcd.c	optional vt
+dev/hdmi/dwc_hdmi.c		optional hdmi iicbus
+dev/hdmi/dwc_hdmi_fdt.c		optional hdmi iicbus
 
 mips/ingenic/jz4780_clock.c	standard
 mips/ingenic/jz4780_clk_gen.c	standard
@@ -25,3 +28,6 @@ mips/ingenic/jz4780_mpboot.S	optional sm
 
 # Custom interface between pinctrl and gpio
 mips/ingenic/jz4780_gpio_if.m	standard
+
+# HDMI interface
+dev/hdmi/hdmi_if.m		standard

Added: head/sys/mips/ingenic/jz4780_lcd.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/ingenic/jz4780_lcd.c	Tue Dec 20 01:51:09 2016	(r310308)
@@ -0,0 +1,572 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Ingenic JZ4780 LCD Controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/fbio.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <mips/ingenic/jz4780_lcd.h>
+
+#include "fb_if.h"
+#include "hdmi_if.h"
+
+#define	FB_DEFAULT_W	800
+#define	FB_DEFAULT_H	600
+#define	FB_DEFAULT_REF	60
+#define	FB_BPP		32
+#define	FB_ALIGN	(16 * 4)
+#define	FB_MAX_BW	(1920 * 1080 * 60)
+#define	FB_MAX_W	2048
+#define	FB_MAX_H	2048
+#define FB_DIVIDE(x, y)	(((x) + ((y) / 2)) / (y))
+
+#define	PCFG_MAGIC	0xc7ff2100
+
+#define	DOT_CLOCK_TO_HZ(c)	((c) * 1000)
+
+#ifndef VM_MEMATTR_WRITE_COMBINING
+#define	VM_MEMATTR_WRITE_COMBINING VM_MEMATTR_UNCACHEABLE
+#endif
+
+struct jzlcd_softc {
+	device_t		dev;
+	device_t		fbdev;
+	struct resource		*res[1];
+
+	/* Clocks */
+	clk_t			clk;
+	clk_t			clk_pix;
+
+	/* Framebuffer */
+	struct fb_info		info;
+	size_t			fbsize;
+	bus_addr_t		paddr;
+	vm_offset_t		vaddr;
+
+	/* HDMI */
+	eventhandler_tag	hdmi_evh;
+
+	/* Frame descriptor DMA */
+	bus_dma_tag_t		fdesc_tag;
+	bus_dmamap_t		fdesc_map;
+	bus_addr_t		fdesc_paddr;
+	struct lcd_frame_descriptor	*fdesc;
+};
+
+static struct resource_spec jzlcd_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+#define	LCD_READ(sc, reg)		bus_read_4((sc)->res[0], (reg))
+#define	LCD_WRITE(sc, reg, val)		bus_write_4((sc)->res[0], (reg), (val))
+
+static int
+jzlcd_allocfb(struct jzlcd_softc *sc)
+{
+	sc->vaddr = kmem_alloc_contig(kernel_arena, sc->fbsize,
+	    M_NOWAIT | M_ZERO, 0, ~0, FB_ALIGN, 0, VM_MEMATTR_WRITE_COMBINING);
+	if (sc->vaddr == 0) {
+		device_printf(sc->dev, "failed to allocate FB memory\n");
+		return (ENOMEM);
+	}
+	sc->paddr = pmap_kextract(sc->vaddr);
+
+	return (0);
+}
+
+static void
+jzlcd_freefb(struct jzlcd_softc *sc)
+{
+	kmem_free(kernel_arena, sc->vaddr, sc->fbsize);
+}
+
+static void
+jzlcd_start(struct jzlcd_softc *sc)
+{
+	uint32_t ctrl;
+
+	/* Clear status registers */
+	LCD_WRITE(sc, LCDSTATE, 0);
+	LCD_WRITE(sc, LCDOSDS, 0);
+	/* Enable the controller */
+	ctrl = LCD_READ(sc, LCDCTRL);
+	ctrl |= LCDCTRL_ENA;
+	ctrl &= ~LCDCTRL_DIS;
+	LCD_WRITE(sc, LCDCTRL, ctrl);
+}
+
+static void
+jzlcd_stop(struct jzlcd_softc *sc)
+{
+	uint32_t ctrl;
+
+	ctrl = LCD_READ(sc, LCDCTRL);
+	if ((ctrl & LCDCTRL_ENA) != 0) {
+		/* Disable the controller and wait for it to stop */
+		ctrl |= LCDCTRL_DIS;
+		LCD_WRITE(sc, LCDCTRL, ctrl);
+		while ((LCD_READ(sc, LCDSTATE) & LCDSTATE_LDD) == 0)
+			DELAY(100);
+	}
+	/* Clear all status except for disable */
+	LCD_WRITE(sc, LCDSTATE, LCD_READ(sc, LCDSTATE) & ~LCDSTATE_LDD);
+}
+
+static void
+jzlcd_setup_descriptor(struct jzlcd_softc *sc, const struct videomode *mode,
+    u_int desno)
+{
+	struct lcd_frame_descriptor *fdesc;
+	int line_sz;
+
+	/* Frame size is specified in # words */
+	line_sz = (mode->hdisplay * FB_BPP) >> 3;
+	line_sz = ((line_sz + 3) & ~3) / 4;
+
+	fdesc = sc->fdesc + desno;
+
+	if (desno == 0)
+		fdesc->next = sc->fdesc_paddr +
+		    sizeof(struct lcd_frame_descriptor);
+	else
+		fdesc->next = sc->fdesc_paddr;
+	fdesc->physaddr = sc->paddr;
+	fdesc->id = desno;
+	fdesc->cmd = LCDCMD_FRM_EN | (line_sz * mode->vdisplay);
+	fdesc->offs = 0;
+	fdesc->pw = 0;
+	fdesc->cnum_pos = LCDPOS_BPP01_18_24 |
+	    LCDPOS_PREMULTI01 |
+	    (desno == 0 ? LCDPOS_COEF_BLE01_1 : LCDPOS_COEF_SLE01);
+	fdesc->dessize = LCDDESSIZE_ALPHA |
+	    ((mode->vdisplay - 1) << LCDDESSIZE_HEIGHT_SHIFT) |
+	    ((mode->hdisplay - 1) << LCDDESSIZE_WIDTH_SHIFT);
+}
+
+static int
+jzlcd_set_videomode(struct jzlcd_softc *sc, const struct videomode *mode)
+{
+	u_int hbp, hfp, hsw, vbp, vfp, vsw;
+	u_int hds, hde, ht, vds, vde, vt;
+	uint32_t ctrl;
+	int error;
+
+	hbp = mode->htotal - mode->hsync_end;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vbp = mode->vtotal - mode->vsync_end;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vsw = mode->vsync_end - mode->vsync_start;
+
+	hds = hsw + hbp;
+	hde = hds + mode->hdisplay;
+	ht = hde + hfp;
+
+	vds = vsw + vbp;
+	vde = vds + mode->vdisplay;
+	vt = vde + vfp;
+
+	/* Setup timings */
+	LCD_WRITE(sc, LCDVAT,
+	    (ht << LCDVAT_HT_SHIFT) | (vt << LCDVAT_VT_SHIFT));
+	LCD_WRITE(sc, LCDDAH,
+	    (hds << LCDDAH_HDS_SHIFT) | (hde << LCDDAH_HDE_SHIFT));
+	LCD_WRITE(sc, LCDDAV,
+	    (vds << LCDDAV_VDS_SHIFT) | (vde << LCDDAV_VDE_SHIFT));
+	LCD_WRITE(sc, LCDHSYNC, hsw);
+	LCD_WRITE(sc, LCDVSYNC, vsw);
+
+	/* Set configuration */
+	LCD_WRITE(sc, LCDCFG, LCDCFG_NEWDES | LCDCFG_RECOVER | LCDCFG_24 |
+	    LCDCFG_PSM | LCDCFG_CLSM | LCDCFG_SPLM | LCDCFG_REVM | LCDCFG_PCP);
+	ctrl = LCD_READ(sc, LCDCTRL);
+	ctrl &= ~LCDCTRL_BST;
+	ctrl |= LCDCTRL_BST_64 | LCDCTRL_OFUM;
+	LCD_WRITE(sc, LCDCTRL, ctrl);
+	LCD_WRITE(sc, LCDPCFG, PCFG_MAGIC);
+	LCD_WRITE(sc, LCDRGBC, LCDRGBC_RGBFMT);
+
+	/* Update registers */
+	LCD_WRITE(sc, LCDSTATE, 0);
+
+	/* Setup frame descriptors */
+	jzlcd_setup_descriptor(sc, mode, 0);
+	jzlcd_setup_descriptor(sc, mode, 1);
+	bus_dmamap_sync(sc->fdesc_tag, sc->fdesc_map, BUS_DMASYNC_PREWRITE);
+
+	/* Setup DMA channels */
+	LCD_WRITE(sc, LCDDA0, sc->fdesc_paddr
+	    + sizeof(struct lcd_frame_descriptor));
+	LCD_WRITE(sc, LCDDA1, sc->fdesc_paddr);
+
+	/* Set display clock */
+	error = clk_set_freq(sc->clk_pix, DOT_CLOCK_TO_HZ(mode->dot_clock), 0);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to set pixel clock to %u Hz\n",
+		    DOT_CLOCK_TO_HZ(mode->dot_clock));
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+jzlcd_configure(struct jzlcd_softc *sc, const struct videomode *mode)
+{
+	size_t fbsize;
+	int error;
+
+	fbsize = round_page(mode->hdisplay * mode->vdisplay * (FB_BPP / NBBY));
+
+	/* Detach the old FB device */
+	if (sc->fbdev != NULL) {
+		device_delete_child(sc->dev, sc->fbdev);
+		sc->fbdev = NULL;
+	}
+
+	/* If the FB size has changed, free the old FB memory */
+	if (sc->fbsize > 0 && sc->fbsize != fbsize) {
+		jzlcd_freefb(sc);
+		sc->vaddr = 0;
+	}
+
+	/* Allocate the FB if necessary */
+	sc->fbsize = fbsize;
+	if (sc->vaddr == 0) {
+		error = jzlcd_allocfb(sc);
+		if (error != 0) {
+			device_printf(sc->dev, "failed to allocate FB memory\n");
+			return (ENXIO);
+		}
+	}
+
+	/* Setup video mode */
+	error = jzlcd_set_videomode(sc, mode);
+	if (error != 0)
+		return (error);
+
+	/* Attach framebuffer device */
+	sc->info.fb_name = device_get_nameunit(sc->dev);
+	sc->info.fb_vbase = (intptr_t)sc->vaddr;
+	sc->info.fb_pbase = sc->paddr;
+	sc->info.fb_size = sc->fbsize;
+	sc->info.fb_bpp = sc->info.fb_depth = FB_BPP;
+	sc->info.fb_stride = mode->hdisplay * (FB_BPP / NBBY);
+	sc->info.fb_width = mode->hdisplay;
+	sc->info.fb_height = mode->vdisplay;
+
+	sc->fbdev = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
+	if (sc->fbdev == NULL) {
+		device_printf(sc->dev, "failed to add fbd child\n");
+		return (ENOENT);
+	}
+
+	error = device_probe_and_attach(sc->fbdev);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to attach fbd device\n");
+		return (error);
+	}
+
+	return (0);
+}
+
+static int
+jzlcd_get_bandwidth(const struct videomode *mode)
+{
+	int refresh;
+
+	refresh = FB_DIVIDE(FB_DIVIDE(DOT_CLOCK_TO_HZ(mode->dot_clock),
+	    mode->htotal), mode->vtotal);
+
+	return mode->hdisplay * mode->vdisplay * refresh;
+}
+
+static int
+jzlcd_mode_supported(const struct videomode *mode)
+{
+	/* Width and height must be less than 2048 */
+	if (mode->hdisplay > FB_MAX_W || mode->vdisplay > FB_MAX_H)
+		return (0);
+
+	/* Bandwidth check */
+	if (jzlcd_get_bandwidth(mode) > FB_MAX_BW)
+		return (0);
+
+	/* Interlace modes not yet supported by the driver */
+	if ((mode->flags & VID_INTERLACE) != 0)
+		return (0);
+
+	return (1);
+}
+
+static const struct videomode *
+jzlcd_find_mode(struct edid_info *ei)
+{
+	const struct videomode *best;
+	int n, bw, best_bw;
+
+	/* If the preferred mode is OK, just use it */
+	if (jzlcd_mode_supported(ei->edid_preferred_mode) != 0)
+		return ei->edid_preferred_mode;
+
+	/* Pick the mode with the highest bandwidth requirements */
+	best = NULL;
+	best_bw = 0;
+	for (n = 0; n < ei->edid_nmodes; n++) {
+		if (jzlcd_mode_supported(&ei->edid_modes[n]) == 0)
+			continue;
+		bw = jzlcd_get_bandwidth(&ei->edid_modes[n]);
+		if (bw > FB_MAX_BW)
+			continue;
+		if (best == NULL || bw > best_bw) {
+			best = &ei->edid_modes[n];
+			best_bw = bw;
+		}
+	}
+
+	return best;
+}
+
+static void
+jzlcd_hdmi_event(void *arg, device_t hdmi_dev)
+{
+	const struct videomode *mode;
+	struct videomode hdmi_mode;
+	struct jzlcd_softc *sc;
+	struct edid_info ei;
+	uint8_t *edid;
+	uint32_t edid_len;
+	int error;
+
+	sc = arg;
+	edid = NULL;
+	edid_len = 0;
+	mode = NULL;
+
+	error = HDMI_GET_EDID(hdmi_dev, &edid, &edid_len);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to get EDID: %d\n", error);
+	} else {
+		error = edid_parse(edid, &ei);
+		if (error != 0) {
+			device_printf(sc->dev, "failed to parse EDID: %d\n",
+			    error);
+		} else {
+			if (bootverbose)
+				edid_print(&ei);
+
+			mode = jzlcd_find_mode(&ei);
+		}
+	}
+
+	/* If a suitable mode could not be found, try the default */
+	if (mode == NULL)
+		mode = pick_mode_by_ref(FB_DEFAULT_W, FB_DEFAULT_H,
+		    FB_DEFAULT_REF);
+
+	if (mode == NULL) {
+		device_printf(sc->dev, "failed to find usable video mode\n");
+		return;
+	}
+
+	if (bootverbose)
+		device_printf(sc->dev, "using %dx%d\n",
+		    mode->hdisplay, mode->vdisplay);
+
+	/* Stop the controller */
+	jzlcd_stop(sc);
+
+	/* Configure LCD controller */
+	error = jzlcd_configure(sc, mode);
+	if (error != 0) {
+		device_printf(sc->dev, "failed to configure FB: %d\n", error);
+		return;
+	}
+
+	/* Enable HDMI TX */
+	hdmi_mode = *mode;
+	HDMI_SET_VIDEOMODE(hdmi_dev, &hdmi_mode);
+
+	/* Start the controller! */
+	jzlcd_start(sc);
+}
+
+static void
+jzlcd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	if (error != 0)
+		return;
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+static int
+jzlcd_probe(device_t dev)
+{
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-lcd"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Ingenic JZ4780 LCD Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+jzlcd_attach(device_t dev)
+{
+	struct jzlcd_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	sc->dev = dev;
+
+	if (bus_alloc_resources(dev, jzlcd_spec, sc->res)) {
+		device_printf(dev, "cannot allocate resources for device\n");
+		goto failed;
+	}
+
+	if (clk_get_by_ofw_name(dev, 0, "lcd_clk", &sc->clk) != 0 ||
+	    clk_get_by_ofw_name(dev, 0, "lcd_pixclk", &sc->clk_pix) != 0) {
+		device_printf(dev, "cannot get clocks\n");
+		goto failed;
+	}
+	if (clk_enable(sc->clk) != 0 || clk_enable(sc->clk_pix) != 0) {
+		device_printf(dev, "cannot enable clocks\n");
+		goto failed;
+	}
+
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),
+	    sizeof(struct lcd_frame_descriptor), 0,
+	    BUS_SPACE_MAXADDR_32BIT,
+	    BUS_SPACE_MAXADDR,
+	    NULL, NULL,
+	    sizeof(struct lcd_frame_descriptor) * 2, 1,
+	    sizeof(struct lcd_frame_descriptor) * 2,
+	    0,
+	    NULL, NULL,
+	    &sc->fdesc_tag);
+	if (error != 0) {
+		device_printf(dev, "cannot create bus dma tag\n");
+		goto failed;
+	}
+
+	error = bus_dmamem_alloc(sc->fdesc_tag, (void **)&sc->fdesc,
+	    BUS_DMA_NOCACHE | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->fdesc_map);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate dma descriptor\n");
+		goto dmaalloc_failed;
+	}
+
+	error = bus_dmamap_load(sc->fdesc_tag, sc->fdesc_map, sc->fdesc,
+	    sizeof(struct lcd_frame_descriptor) * 2, jzlcd_dmamap_cb,
+	    &sc->fdesc_paddr, 0);
+	if (error != 0) {
+		device_printf(dev, "cannot load dma map\n");
+		goto dmaload_failed;
+	}
+
+	sc->hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event,
+	    jzlcd_hdmi_event, sc, 0);
+
+	return (0);
+
+dmaload_failed:
+	bus_dmamem_free(sc->fdesc_tag, sc->fdesc, sc->fdesc_map);
+dmaalloc_failed:
+	bus_dma_tag_destroy(sc->fdesc_tag);
+failed:
+	if (sc->clk_pix != NULL)
+		clk_release(sc->clk);
+	if (sc->clk != NULL)
+		clk_release(sc->clk);
+	if (sc->res != NULL)
+		bus_release_resources(dev, jzlcd_spec, sc->res);
+
+	return (ENXIO);
+}
+
+static struct fb_info *
+jzlcd_fb_getinfo(device_t dev)
+{
+	struct jzlcd_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (&sc->info);
+}
+
+static device_method_t jzlcd_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		jzlcd_probe),
+	DEVMETHOD(device_attach,	jzlcd_attach),
+
+	/* FB interface */
+	DEVMETHOD(fb_getinfo,		jzlcd_fb_getinfo),
+
+	DEVMETHOD_END
+};
+
+static driver_t jzlcd_driver = {
+	"fb",
+	jzlcd_methods,
+	sizeof(struct jzlcd_softc),
+};
+
+static devclass_t jzlcd_devclass;
+
+DRIVER_MODULE(fb, simplebus, jzlcd_driver, jzlcd_devclass, 0, 0);

Added: head/sys/mips/ingenic/jz4780_lcd.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/ingenic/jz4780_lcd.h	Tue Dec 20 01:51:09 2016	(r310308)
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill at invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Ingenic JZ4780 LCD Controller
+ */
+
+#ifndef __JZ4780_LCD_H__
+#define __JZ4780_LCD_H__
+
+#define	LCDCFG			0x0000
+#define	 LCDCFG_LCDPIN		(1 << 31)
+#define	 LCDCFG_TVEPEH		(1 << 30)
+#define	 LCDCFG_NEWDES		(1 << 28)
+#define	 LCDCFG_PALBP		(1 << 27)
+#define	 LCDCFG_TVEN		(1 << 26)
+#define	 LCDCFG_RECOVER		(1 << 25)
+#define	 LCDCFG_PSM		(1 << 23)
+#define	 LCDCFG_CLSM		(1 << 22)
+#define	 LCDCFG_SPLM		(1 << 21)
+#define	 LCDCFG_REVM		(1 << 20)
+#define	 LCDCFG_HSYNM		(1 << 19)
+#define	 LCDCFG_VSYNM		(1 << 18)
+#define	 LCDCFG_INVDAT		(1 << 17)
+#define	 LCDCFG_SYNDIR		(1 << 16)
+#define	 LCDCFG_PSP		(1 << 15)
+#define	 LCDCFG_CLSP		(1 << 14)
+#define	 LCDCFG_SPLP		(1 << 13)
+#define	 LCDCFG_REVP		(1 << 12)
+#define	 LCDCFG_HSP		(1 << 11)
+#define	 LCDCFG_PCP		(1 << 10)
+#define	 LCDCFG_DEP		(1 << 9)
+#define	 LCDCFG_VSP		(1 << 8)
+#define	 LCDCFG_18_16		(1 << 7)
+#define	 LCDCFG_24		(1 << 6)
+#define	 LCDCFG_MODE		(0xf << 0)
+#define	LCDCTRL			0x0030
+#define	 LCDCTRL_PINMD		(1 << 31)
+#define	 LCDCTRL_BST		(0x7 << 28)
+#define	  LCDCTRL_BST_4		(0 << 28)
+#define	  LCDCTRL_BST_8		(1 << 28)
+#define	  LCDCTRL_BST_16	(2 << 28)
+#define	  LCDCTRL_BST_32	(3 << 28)
+#define	  LCDCTRL_BST_64	(4 << 28)
+#define	 LCDCTRL_OUTRGB		(1 << 27)
+#define	 LCDCTRL_OFUP		(1 << 26)
+#define	 LCDCTRL_DACTE		(1 << 14)
+#define	 LCDCTRL_EOFM		(1 << 13)
+#define	 LCDCTRL_SOFM		(1 << 12)
+#define	 LCDCTRL_OFUM		(1 << 11)
+#define	 LCDCTRL_IFUM0		(1 << 10)
+#define	 LCDCTRL_IFUM1		(1 << 9)
+#define	 LCDCTRL_LDDM		(1 << 8)
+#define	 LCDCTRL_QDM		(1 << 7)
+#define	 LCDCTRL_BEDN		(1 << 6)
+#define	 LCDCTRL_PEDN		(1 << 5)
+#define	 LCDCTRL_DIS		(1 << 4)
+#define	 LCDCTRL_ENA		(1 << 3)
+#define	 LCDCTRL_BPP0		(0x7 << 0)
+#define	  LCDCTRL_BPP0_1	(0 << 0)
+#define	  LCDCTRL_BPP0_2	(1 << 0)
+#define	  LCDCTRL_BPP0_4	(2 << 0)
+#define	  LCDCTRL_BPP0_8	(3 << 0)
+#define	  LCDCTRL_BPP0_15_16	(4 << 0)
+#define	  LCDCTRL_BPP0_18_24	(5 << 0)
+#define	  LCDCTRL_BPP0_24_COMP	(6 << 0)
+#define	  LCDCTRL_BPP0_30	(7 << 0)
+#define	 LCDCTR
+#define	LCDSTATE		0x0034
+#define	 LCDSTATE_QD		(1 << 7)
+#define	 LCDSTATE_EOF		(1 << 5)
+#define	 LCDSTATE_SOF		(1 << 4)
+#define	 LCDSTATE_OUT		(1 << 3)
+#define	 LCDSTATE_IFU0		(1 << 2)
+#define	 LCDSTATE_IFU1		(1 << 1)
+#define	 LCDSTATE_LDD		(1 << 0)
+#define	LCDOSDC			0x0100
+#define	LCDOSDCTRL		0x0104
+#define	LCDOSDS			0x0108
+#define	LCDBGC0			0x010c
+#define	LCDBGC1			0x02c4
+#define	LCDKEY0			0x0110
+#define	LCDKEY1			0x0114
+#define	LCDALPHA		0x0118
+#define	LCDIPUR			0x011c
+#define	LCDRGBC			0x0090
+#define	 LCDRGBC_RGBDM		(1 << 15)
+#define	 LCDRGBC_DMM		(1 << 14)
+#define	 LCDRGBC_422		(1 << 8)
+#define	 LCDRGBC_RGBFMT		(1 << 7)
+#define	 LCDRGBC_ODDRGB		(0x7 << 4)
+#define	 LCDRGBC_EVENRGB	(0x7 << 0)
+#define	LCDVAT			0x000c
+#define	 LCDVAT_HT_SHIFT	16
+#define	 LCDVAT_VT_SHIFT	0
+#define	LCDDAH			0x0010
+#define	 LCDDAH_HDS_SHIFT	16
+#define	 LCDDAH_HDE_SHIFT	0
+#define	LCDDAV			0x0014
+#define	 LCDDAV_VDS_SHIFT	16
+#define	 LCDDAV_VDE_SHIFT	0
+#define	LCDXYP0			0x0120
+#define	LCDXYP1			0x0124
+#define	LCDSIZE0		0x0128
+#define	LCDSIZE1		0x012c
+#define	LCDVSYNC		0x0004
+#define	LCDHSYNC		0x0008
+#define	LCDPS			0x0018
+#define	LCDCLS			0x001c
+#define	LCDSPL			0x0020
+#define	LCDREV			0x0024
+#define	LCDIID			0x0038
+#define	LCDDA0			0x0040
+#define	LCDSA0			0x0044
+#define	LCDFID0			0x0048
+#define	LCDCMD0			0x004c
+#define	 LCDCMD_SOFINT		(1 << 31)
+#define	 LCDCMD_EOFINT		(1 << 30)
+#define	 LCDCMD_CMD		(1 << 29)
+#define	 LCDCMD_COMPE		(1 << 27)
+#define	 LCDCMD_FRM_EN		(1 << 26)
+#define	 LCDCMD_FIELD_SEL	(1 << 25)
+#define	 LCDCMD_16X16BLOCK	(1 << 24)
+#define	 LCDCMD_LEN		(0xffffff << 0)
+#define	LCDOFFS0		0x0060
+#define	LCDPW0			0x0064
+#define	LCDCNUM0		0x0068
+#define	LCDPOS0			LCDCNUM0
+#define	 LCDPOS_ALPHAMD1	(1 << 31)
+#define	 LCDPOS_RGB01		(1 << 30)
+#define	 LCDPOS_BPP01		(0x7 << 27)
+#define	  LCDPOS_BPP01_15_16	(4 << 27)
+#define	  LCDPOS_BPP01_18_24	(5 << 27)
+#define	  LCDPOS_BPP01_24_COMP	(6 << 27)
+#define	  LCDPOS_BPP01_30	(7 << 27)
+#define	  LCDPOS_PREMULTI01	(1 << 26)
+#define	  LCDPOS_COEF_SLE01	(0x3 << 24)
+#define	  LCDPOS_COEF_BLE01_1	(1 << 24)
+#define	  LCDPOS_YPOS01		(0xfff << 12)
+#define	  LCDPOS_XPOS01		(0xfff << 0)
+#define	LCDDESSIZE0		0x006c
+#define	 LCDDESSIZE_ALPHA	(0xff << 24)
+#define	 LCDDESSIZE_HEIGHT	(0xfff << 12)
+#define	 LCDDESSIZE_HEIGHT_SHIFT 12
+#define	 LCDDESSIZE_WIDTH	(0xfff << 0)
+#define	 LCDDESSIZE_WIDTH_SHIFT	0
+#define	LCDDA1			0x0050
+#define	LCDSA1			0x0054
+#define	LCDFID1			0x0058
+#define	LCDCMD1			0x005c
+#define	LCDOFFS1		0x0070
+#define	LCDPW1			0x0074
+#define	LCDCNUM1		0x0078
+#define	LCDPOS1			LCDCNUM1
+#define	LCDDESSIZE1		0x007c
+#define	LCDPCFG			0x02c0
+#define	LCDDUALCTRL		0x02c8
+#define	LCDENH_CFG		0x0400
+#define	LCDENH_CSCCFG		0x0404
+#define	LCDENH_LUMACFG		0x0408
+#define	LCDENH_CHROCFG0		0x040c
+#define	LCDENH_CHROCFG1		0x0410
+#define	LCDENH_DITHERCFG	0x0414
+#define	LCDENH_STATUS		0x0418
+#define	LCDENH_GAMMA		0x0800	/* base */
+#define	LCDENH_VEE		0x1000	/* base */
+
+struct lcd_frame_descriptor {
+	uint32_t	next;
+	uint32_t	physaddr;
+	uint32_t	id;
+	uint32_t	cmd;
+	uint32_t	offs;
+	uint32_t	pw;
+	uint32_t	cnum_pos;
+	uint32_t	dessize;
+} __packed;
+
+#endif /* !__JZ4780_LCD_H__ */


More information about the svn-src-head mailing list