Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142726145
D8827.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
D8827.id.diff
View Options
Index: head/sys/mips/conf/JZ4780
===================================================================
--- head/sys/mips/conf/JZ4780
+++ head/sys/mips/conf/JZ4780
@@ -86,6 +86,16 @@
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 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
Index: head/sys/mips/ingenic/files.jz4780
===================================================================
--- head/sys/mips/ingenic/files.jz4780
+++ head/sys/mips/ingenic/files.jz4780
@@ -6,6 +6,9 @@
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 @@
# Custom interface between pinctrl and gpio
mips/ingenic/jz4780_gpio_if.m standard
+
+# HDMI interface
+dev/hdmi/hdmi_if.m standard
Index: head/sys/mips/ingenic/jz4780_lcd.h
===================================================================
--- head/sys/mips/ingenic/jz4780_lcd.h
+++ head/sys/mips/ingenic/jz4780_lcd.h
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@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__ */
Index: head/sys/mips/ingenic/jz4780_lcd.c
===================================================================
--- head/sys/mips/ingenic/jz4780_lcd.c
+++ head/sys/mips/ingenic/jz4780_lcd.c
@@ -0,0 +1,572 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 23, 6:04 PM (9 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27887500
Default Alt Text
D8827.id.diff (22 KB)
Attached To
Mode
D8827: jz4780 LCD controller driver
Attached
Detach File
Event Timeline
Log In to Comment