Add support for Ingenic JZ4780 LCD controller and enable framebuffer
console support. Reviewed by: kan Differential Revision: https://reviews.freebsd.org/D8827
This commit is contained in:
parent
8ee54cadae
commit
964670595f
@ -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 controller
|
||||
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
|
||||
|
@ -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 smp
|
||||
|
||||
# Custom interface between pinctrl and gpio
|
||||
mips/ingenic/jz4780_gpio_if.m standard
|
||||
|
||||
# HDMI interface
|
||||
dev/hdmi/hdmi_if.m standard
|
||||
|
572
sys/mips/ingenic/jz4780_lcd.c
Normal file
572
sys/mips/ingenic/jz4780_lcd.c
Normal file
@ -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);
|
204
sys/mips/ingenic/jz4780_lcd.h
Normal file
204
sys/mips/ingenic/jz4780_lcd.h
Normal file
@ -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__ */
|
Loading…
x
Reference in New Issue
Block a user