[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v5 19/24] hw/arm: add Faraday FTLCDC200 LCD controll
From: |
Kuo-Jung Su |
Subject: |
[Qemu-devel] [PATCH v5 19/24] hw/arm: add Faraday FTLCDC200 LCD controller support |
Date: |
Wed, 27 Feb 2013 15:15:45 +0800 |
From: Kuo-Jung Su <address@hidden>
The FTLCDC200 Color LCD controller performs translation of
pixel-coded data into the required formats and timings to
drive a variety of single/dual mono and color LCDs.
Depending on the LCD type and mode, the unpacked data can represent:
1. an actual true display gray or color value
2. an address to a 256 x 16 bit wide palette RAM gray or color value.
The FTLCDC200 generates 4 individual interrupts for:
1. DMA FIFO underflow
2. base address update
3. vertical status
4. bus error.
There is also a single combined interrupt that is raised when any of
the individual interrupts become active.
Signed-off-by: Kuo-Jung Su <address@hidden>
---
hw/arm/Makefile.objs | 1 +
hw/arm/faraday_a369_soc.c | 10 +
hw/arm/ftlcdc200.c | 513 +++++++++++++++++++++++++++++++++++++++++++
hw/arm/ftlcdc200.h | 110 ++++++++++
hw/arm/ftlcdc200_template.h | 439 ++++++++++++++++++++++++++++++++++++
5 files changed, 1073 insertions(+)
create mode 100644 hw/arm/ftlcdc200.c
create mode 100644 hw/arm/ftlcdc200.h
create mode 100644 hw/arm/ftlcdc200_template.h
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 154e2ea..5630956 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -49,3 +49,4 @@ obj-y += ftnandc021.o
obj-y += fti2c010.o
obj-y += ftssp010.o
obj-y += ftgmac100.o
+obj-y += ftlcdc200.o
diff --git a/hw/arm/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
index d31049e..d39bf1d 100644
--- a/hw/arm/faraday_a369_soc.c
+++ b/hw/arm/faraday_a369_soc.c
@@ -252,6 +252,16 @@ a369soc_device_init(FaradaySoCState *s)
done_nic = 1;
}
}
+
+ /* ftlcdc200 */
+ sysbus_create_varargs("ftlcdc200",
+ 0x94a00000,
+ pic[0], /* ALL (NC in A369) */
+ pic[25], /* VSTATUS */
+ pic[24], /* Base Address Update */
+ pic[23], /* FIFO Under-Run */
+ pic[22], /* AHB Bus Error */
+ NULL);
}
static int a369soc_init(SysBusDevice *busdev)
diff --git a/hw/arm/ftlcdc200.c b/hw/arm/ftlcdc200.c
new file mode 100644
index 0000000..76e761c
--- /dev/null
+++ b/hw/arm/ftlcdc200.c
@@ -0,0 +1,513 @@
+/*
+ * Faraday FTLCDC200 Color LCD Controller
+ *
+ * base is pl110.c
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * This code is licensed under the GNU LGPL
+ */
+
+#include "hw/sysbus.h"
+#include "hw/framebuffer.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+
+#include "faraday.h"
+#include "ftlcdc200.h"
+
+enum ftlcdc200_irqpin {
+ IRQ_ALL = 0,
+ IRQ_VSTATUS,
+ IRQ_BASEUPT,
+ IRQ_FIFOUR,
+ IRQ_BUSERR,
+};
+
+enum ftlcdc200_bppmode {
+ BPP_1 = 0,
+ BPP_2,
+ BPP_4,
+ BPP_8,
+ BPP_16,
+ BPP_32,
+ BPP_16_565,
+ BPP_12,
+};
+
+#define TYPE_FTLCDC200 "ftlcdc200"
+
+typedef struct Ftlcdc200State {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ DisplayState *ds;
+ qemu_irq irq[5];
+ int cols;
+ int rows;
+ enum ftlcdc200_bppmode bpp;
+ int invalidate;
+ uint32_t palette[256];
+ uint32_t raw_palette[128];
+
+ /* hw register caches */
+ uint32_t fer; /* function enable register */
+ uint32_t ppr; /* panel pixel register */
+ uint32_t ier; /* interrupt enable register */
+ uint32_t isr; /* interrupt status register */
+ uint32_t sppr; /* serail panel pixel register */
+
+ uint32_t fb[4]; /* frame buffer base address register */
+ uint32_t ht; /* horizontal timing control register */
+ uint32_t vt0; /* vertital timing control register 0 */
+ uint32_t vt1; /* vertital timing control register 1 */
+ uint32_t pol; /* polarity */
+
+} Ftlcdc200State;
+
+#define FTLCDC200(obj) \
+ OBJECT_CHECK(Ftlcdc200State, obj, TYPE_FTLCDC200)
+
+static const VMStateDescription vmstate_ftlcdc200 = {
+ .name = TYPE_FTLCDC200,
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(cols, Ftlcdc200State),
+ VMSTATE_INT32(rows, Ftlcdc200State),
+ VMSTATE_UINT32(bpp, Ftlcdc200State),
+ VMSTATE_INT32(invalidate, Ftlcdc200State),
+ VMSTATE_UINT32_ARRAY(palette, Ftlcdc200State, 256),
+ VMSTATE_UINT32_ARRAY(raw_palette, Ftlcdc200State, 128),
+ VMSTATE_UINT32(fer, Ftlcdc200State),
+ VMSTATE_UINT32(ppr, Ftlcdc200State),
+ VMSTATE_UINT32(ier, Ftlcdc200State),
+ VMSTATE_UINT32(isr, Ftlcdc200State),
+ VMSTATE_UINT32(sppr, Ftlcdc200State),
+ VMSTATE_UINT32_ARRAY(fb, Ftlcdc200State, 4),
+ VMSTATE_UINT32(ht, Ftlcdc200State),
+ VMSTATE_UINT32(vt0, Ftlcdc200State),
+ VMSTATE_UINT32(vt1, Ftlcdc200State),
+ VMSTATE_UINT32(pol, Ftlcdc200State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define BITS 8
+#include "ftlcdc200_template.h"
+#define BITS 15
+#include "ftlcdc200_template.h"
+#define BITS 16
+#include "ftlcdc200_template.h"
+#define BITS 24
+#include "ftlcdc200_template.h"
+#define BITS 32
+#include "ftlcdc200_template.h"
+
+static int ftlcdc200_enabled(Ftlcdc200State *s)
+{
+ uint32_t mask = FER_EN | FER_ON;
+ return ((s->fer & mask) == mask)
+ && s->bpp && s->cols && s->rows && s->fb[0];
+}
+
+/* Update interrupts. */
+static void ftlcdc200_update_irq(Ftlcdc200State *s)
+{
+ uint32_t mask = s->ier & s->isr;
+
+ if (mask) {
+ qemu_irq_raise(s->irq[IRQ_ALL]);
+ qemu_set_irq(s->irq[IRQ_FIFOUR], (mask & ISR_FIFOUR) ? 1 : 0);
+ qemu_set_irq(s->irq[IRQ_BASEUPT], (mask & ISR_NEXTFB) ? 1 : 0);
+ qemu_set_irq(s->irq[IRQ_VSTATUS], (mask & ISR_VCOMP) ? 1 : 0);
+ qemu_set_irq(s->irq[IRQ_BUSERR], (mask & ISR_BUSERR) ? 1 : 0);
+ } else {
+ qemu_irq_lower(s->irq[IRQ_ALL]);
+ qemu_irq_lower(s->irq[IRQ_VSTATUS]);
+ qemu_irq_lower(s->irq[IRQ_BASEUPT]);
+ qemu_irq_lower(s->irq[IRQ_FIFOUR]);
+ qemu_irq_lower(s->irq[IRQ_BUSERR]);
+ }
+}
+
+static void ftlcdc200_update_display(void *opaque)
+{
+ Ftlcdc200State *s = FTLCDC200(opaque);
+ drawfn *fntable;
+ drawfn fn;
+ int dest_width;
+ int src_width;
+ int bpp_offset;
+ int first;
+ int last;
+
+ if (!ftlcdc200_enabled(s)) {
+ return;
+ }
+
+ switch (ds_get_bits_per_pixel(s->ds)) {
+ case 0:
+ return;
+ case 8:
+ fntable = ftlcdc200_draw_fn_8;
+ dest_width = 1;
+ break;
+ case 15:
+ fntable = ftlcdc200_draw_fn_15;
+ dest_width = 2;
+ break;
+ case 16:
+ fntable = ftlcdc200_draw_fn_16;
+ dest_width = 2;
+ break;
+ case 24:
+ fntable = ftlcdc200_draw_fn_24;
+ dest_width = 3;
+ break;
+ case 32:
+ fntable = ftlcdc200_draw_fn_32;
+ dest_width = 4;
+ break;
+ default:
+ hw_error("ftlcdc200: Bad color depth\n");
+ exit(1);
+ }
+
+ bpp_offset = 0;
+ fn = fntable[s->bpp + bpp_offset];
+
+ src_width = s->cols;
+ switch (s->bpp) {
+ case BPP_1:
+ src_width >>= 3;
+ break;
+ case BPP_2:
+ src_width >>= 2;
+ break;
+ case BPP_4:
+ src_width >>= 1;
+ break;
+ case BPP_8:
+ break;
+ case BPP_16:
+ case BPP_16_565:
+ case BPP_12:
+ src_width <<= 1;
+ break;
+ case BPP_32:
+ src_width <<= 2;
+ break;
+ }
+ dest_width *= s->cols;
+ first = 0;
+ framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev),
+ s->fb[0], s->cols, s->rows,
+ src_width, dest_width, 0,
+ s->invalidate,
+ fn, s->palette,
+ &first, &last);
+ if (s->ier & (IER_VCOMP | IER_NEXTFB)) {
+ s->isr |= (IER_VCOMP | IER_NEXTFB);
+ ftlcdc200_update_irq(s);
+ }
+ if (first >= 0) {
+ dpy_gfx_update(s->ds, 0, first, s->cols, last - first + 1);
+ }
+ s->invalidate = 0;
+}
+
+static void ftlcdc200_invalidate_display(void *opaque)
+{
+ Ftlcdc200State *s = FTLCDC200(opaque);
+ s->invalidate = 1;
+ if (ftlcdc200_enabled(s)) {
+ qemu_console_resize(s->ds, s->cols, s->rows);
+ }
+}
+
+static void ftlcdc200_update_palette(Ftlcdc200State *s, int n)
+{
+ int i;
+ uint32_t raw;
+ unsigned int r, g, b;
+
+ raw = s->raw_palette[n];
+ n <<= 1;
+ for (i = 0; i < 2; i++) {
+ r = extract32(raw, 0, 5) << 3;
+ g = extract32(raw, 5, 5) << 3;
+ b = extract32(raw, 10, 5) << 3;
+ /* The I bit is ignored. */
+ raw >>= 6;
+ switch (ds_get_bits_per_pixel(s->ds)) {
+ case 8:
+ s->palette[n] = rgb_to_pixel8(r, g, b);
+ break;
+ case 15:
+ s->palette[n] = rgb_to_pixel15(r, g, b);
+ break;
+ case 16:
+ s->palette[n] = rgb_to_pixel16(r, g, b);
+ break;
+ case 24:
+ case 32:
+ s->palette[n] = rgb_to_pixel32(r, g, b);
+ break;
+ }
+ n++;
+ }
+}
+
+static void ftlcdc200_resize(Ftlcdc200State *s, int width, int height)
+{
+ if (width != s->cols || height != s->rows) {
+ if (ftlcdc200_enabled(s)) {
+ qemu_console_resize(s->ds, width, height);
+ }
+ }
+ s->cols = width;
+ s->rows = height;
+}
+
+static uint64_t
+ftlcdc200_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+ Ftlcdc200State *s = FTLCDC200(opaque);
+
+ switch (addr) {
+ case REG_FER:
+ return s->fer;
+ case REG_PPR:
+ return s->ppr;
+ case REG_IER:
+ return s->ier;
+ case REG_ISR:
+ return s->isr;
+ case REG_FB0:
+ return s->fb[0];
+ case REG_FB1:
+ return s->fb[1];
+ case REG_FB2:
+ return s->fb[2];
+ case REG_FB3:
+ return s->fb[3];
+ case REG_HT:
+ return s->ht;
+ case REG_VT0:
+ return s->vt0;
+ case REG_VT1:
+ return s->vt1;
+ case REG_POL:
+ return s->pol;
+ case REG_SPPR:
+ return s->sppr;
+ case 0xA00 ... 0xBFC: /* palette. */
+ return s->raw_palette[(addr - 0xA00) >> 2];
+ case REG_CCIR:
+ case 0x300 ... 0x310: /* image parameters */
+ case 0x400 ... 0x40C: /* color management */
+ case 0x600 ... 0x8FC: /* gamma correction */
+ case 0xC00 ... 0xD3C: /* cstn parameters */
+ case 0x1100 ... 0x112C: /* scalar control */
+ case 0x2000 ... 0xBFFC: /* osd control */
+ return 0;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ftlcdc200: undefined memory address@hidden", addr);
+ return 0;
+ }
+}
+
+static void
+ftlcdc200_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ Ftlcdc200State *s = FTLCDC200(opaque);
+ int n;
+
+ /* For simplicity invalidate the display whenever a control register
+ is written to. */
+ s->invalidate = 1;
+
+ switch (addr) {
+ case REG_FER:
+ s->fer = (uint32_t)val;
+ if (ftlcdc200_enabled(s)) {
+ qemu_console_resize(s->ds, s->cols, s->rows);
+ }
+ break;
+ case REG_PPR:
+ s->ppr = (uint32_t)val;
+ switch (s->ppr & PPR_RGB_MASK) {
+ case PPR_RGB1:
+ s->bpp = BPP_1;
+ break;
+ case PPR_RGB2:
+ s->bpp = BPP_2;
+ break;
+ case PPR_RGB4:
+ s->bpp = BPP_4;
+ break;
+ case PPR_RGB8:
+ s->bpp = BPP_8;
+ break;
+ case PPR_RGB12:
+ s->bpp = BPP_12;
+ break;
+ case PPR_RGB16_555:
+ s->bpp = BPP_16;
+ break;
+ case PPR_RGB16_565:
+ s->bpp = BPP_16_565;
+ break;
+ case PPR_RGB24:
+ default:
+ s->bpp = BPP_32;
+ break;
+ }
+ if (ftlcdc200_enabled(s)) {
+ qemu_console_resize(s->ds, s->cols, s->rows);
+ }
+ break;
+ case REG_IER:
+ s->ier = (uint32_t)val;
+ ftlcdc200_update_irq(s);
+ break;
+ case REG_ISCR:
+ s->isr &= ~((uint32_t)val);
+ ftlcdc200_update_irq(s);
+ break;
+ case REG_FB0:
+ s->fb[0] = (uint32_t)val;
+ break;
+ case REG_FB1:
+ s->fb[1] = (uint32_t)val;
+ break;
+ case REG_FB2:
+ s->fb[2] = (uint32_t)val;
+ break;
+ case REG_FB3:
+ s->fb[3] = (uint32_t)val;
+ break;
+ case REG_HT:
+ s->ht = (uint32_t)val;
+ n = ((s->ht & 0xff) + 1) << 4;
+ ftlcdc200_resize(s, n, s->rows);
+ break;
+ case REG_VT0:
+ s->vt0 = (uint32_t)val;
+ n = (s->vt0 & 0xfff) + 1;
+ ftlcdc200_resize(s, s->cols, n);
+ break;
+ case REG_VT1:
+ s->vt1 = (uint32_t)val;
+ break;
+ case REG_POL:
+ s->pol = (uint32_t)val;
+ break;
+ case REG_SPPR:
+ s->sppr = (uint32_t)val;
+ break;
+ case 0xA00 ... 0xBFC: /* palette. */
+ n = (addr - 0xA00) >> 2;
+ s->raw_palette[(addr - 0xA00) >> 2] = val;
+ ftlcdc200_update_palette(s, n);
+ break;
+ case 0x300 ... 0x310: /* image parameters */
+ case 0x400 ... 0x40C: /* color management */
+ case 0x600 ... 0x8FC: /* gamma correction */
+ case 0xC00 ... 0xD3C: /* cstn parameters */
+ case 0x1100 ... 0x112C: /* scalar control */
+ case 0x2000 ... 0xBFFC: /* osd control */
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ftlcdc200: undefined memory address@hidden", addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps mmio_ops = {
+ .read = ftlcdc200_mem_read,
+ .write = ftlcdc200_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ }
+};
+
+static void ftlcdc200_reset(DeviceState *ds)
+{
+ SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
+ Ftlcdc200State *s = FTLCDC200(FROM_SYSBUS(Ftlcdc200State, busdev));
+
+ s->fer = 0;
+ s->ppr = 0;
+ s->ier = 0;
+ s->isr = 0;
+ s->sppr = 0;
+ s->fb[0] = 0;
+ s->fb[1] = 0;
+ s->fb[2] = 0;
+ s->fb[3] = 0;
+ s->ht = 0;
+ s->vt0 = 0;
+ s->vt1 = 0;
+ s->pol = 0;
+ s->cols = 0;
+ s->rows = 0;
+ s->bpp = 0;
+ s->invalidate = 1;
+
+ memset(s->raw_palette, 0, sizeof(s->raw_palette));
+
+ /* Make sure we redraw, and at the right size */
+ ftlcdc200_invalidate_display(s);
+}
+
+static int ftlcdc200_init(SysBusDevice *dev)
+{
+ Ftlcdc200State *s = FTLCDC200(FROM_SYSBUS(Ftlcdc200State, dev));
+
+ memory_region_init_io(&s->iomem,
+ &mmio_ops,
+ s,
+ TYPE_FTLCDC200,
+ 0x10000);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq[IRQ_ALL]);
+ sysbus_init_irq(dev, &s->irq[IRQ_VSTATUS]);
+ sysbus_init_irq(dev, &s->irq[IRQ_BASEUPT]);
+ sysbus_init_irq(dev, &s->irq[IRQ_FIFOUR]);
+ sysbus_init_irq(dev, &s->irq[IRQ_BUSERR]);
+ s->ds = graphic_console_init(ftlcdc200_update_display,
+ ftlcdc200_invalidate_display,
+ NULL, NULL, s);
+ return 0;
+}
+
+static void ftlcdc200_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ftlcdc200_init;
+ dc->reset = ftlcdc200_reset;
+ dc->vmsd = &vmstate_ftlcdc200;
+ dc->no_user = 1;
+}
+
+static const TypeInfo ftlcdc200_info = {
+ .name = TYPE_FTLCDC200,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Ftlcdc200State),
+ .class_init = ftlcdc200_class_init,
+};
+
+static void ftlcdc200_register_types(void)
+{
+ type_register_static(&ftlcdc200_info);
+}
+
+type_init(ftlcdc200_register_types)
diff --git a/hw/arm/ftlcdc200.h b/hw/arm/ftlcdc200.h
new file mode 100644
index 0000000..53917e1
--- /dev/null
+++ b/hw/arm/ftlcdc200.h
@@ -0,0 +1,110 @@
+/*
+ * Faraday FTLCDC200 Color LCD Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * This code is licensed under the GNU LGPL
+ */
+
+#ifndef HW_ARM_FTLCDC2XX_H
+#define HW_ARM_FTLCDC2XX_H
+
+/* HW Registers */
+
+#define REG_FER 0x00000 /* LCD Function Enable Register */
+#define REG_PPR 0x00004 /* LCD Panel Pixel Register */
+#define REG_IER 0x00008 /* LCD Interrupt Enable Register */
+#define REG_ISCR 0x0000C /* LCD Interrupt Status Clear Register */
+#define REG_ISR 0x00010 /* LCD Interrupt Status Register */
+#define REG_FB0 0x00018 /* LCD Framebuffer Base Register 0 */
+#define REG_FB1 0x00024 /* LCD Framebuffer Base Register 1 */
+#define REG_FB2 0x00030 /* LCD Framebuffer Base Register 2 */
+#define REG_FB3 0x0003C /* LCD Framebuffer Base Register 3 */
+
+#define REG_HT 0x00100 /* LCD Horizontal Timing Control Register */
+#define REG_VT0 0x00104 /* LCD Vertical Timing Control Register 0 */
+#define REG_VT1 0x00108 /* LCD Vertical Timing Control Register 1 */
+#define REG_POL 0x0010C /* LCD Polarity Control Register */
+
+#define REG_SPPR 0x00200 /* LCD Serial Panel Pixel Register */
+#define REG_CCIR 0x00204 /* LCD CCIR565 Register */
+
+/* LCD Function Enable Register */
+#define FER_EN (1 << 0) /* chip enabled */
+#define FER_ON (1 << 1) /* screen on */
+#define FER_YUV420 (3 << 2)
+#define FER_YUV422 (2 << 2)
+#define FER_YUV (1 << 3) /* 1:YUV, 0:RGB */
+
+/* LCD Panel Pixel Register */
+#define PPR_BPP_1 (0 << 0)
+#define PPR_BPP_2 (1 << 0)
+#define PPR_BPP_4 (2 << 0)
+#define PPR_BPP_8 (3 << 0)
+#define PPR_BPP_16 (4 << 0)
+#define PPR_BPP_24 (5 << 0)
+#define PPR_BPP_MASK (7 << 0)
+#define PPR_PWROFF (1 << 3)
+#define PPR_BGR (1 << 4)
+#define PPR_ENDIAN_LBLP (0 << 5)
+#define PPR_ENDIAN_BBBP (1 << 5)
+#define PPR_ENDIAN_LBBP (2 << 5)
+#define PPR_ENDIAN_MASK (3 << 5)
+#define PPR_RGB1 (PPR_BPP_1)
+#define PPR_RGB2 (PPR_BPP_2)
+#define PPR_RGB4 (PPR_BPP_4)
+#define PPR_RGB8 (PPR_BPP_8)
+#define PPR_RGB12 (PPR_BPP_16 | (2 << 7))
+#define PPR_RGB16_555 (PPR_BPP_16 | (1 << 7))
+#define PPR_RGB16_565 (PPR_BPP_16 | (0 << 7))
+#define PPR_RGB24 (PPR_BPP_24)
+#define PPR_RGB32 (PPR_BPP_24)
+#define PPR_RGB_MASK (PPR_BPP_MASK | (3 << 7))
+#define PPR_VCOMP_VSYNC (0 << 9)
+#define PPR_VCOMP_VBP (1 << 9)
+#define PPR_VCOMP_VAIMG (2 << 9)
+#define PPR_VCOMP_VFP (3 << 9)
+#define PPR_VCOMP_MASK (3 << 9)
+
+/* LCD Interrupt Enable Register */
+#define IER_FIFOUR (1 << 0)
+#define IER_NEXTFB (1 << 1)
+#define IER_VCOMP (1 << 2)
+#define IER_BUSERR (1 << 3)
+
+/* LCD Interrupt Status Register */
+#define ISR_FIFOUR (1 << 0)
+#define ISR_NEXTFB (1 << 1)
+#define ISR_VCOMP (1 << 2)
+#define ISR_BUSERR (1 << 3)
+
+/* LCD Horizontal Timing Control Register */
+#define HT_HBP(x) ((((x) - 1) & 0xff) << 24)
+#define HT_HFP(x) ((((x) - 1) & 0xff) << 16)
+#define HT_HSYNC(x) ((((x) - 1) & 0xff) << 8)
+#define HT_PL(x) (((x >> 4) - 1) & 0xff)
+
+/* LCD Vertical Timing Control Register 0 */
+#define VT0_VFP(x) (((x) & 0xff) << 24)
+#define VT0_VSYNC(x) ((((x) - 1) & 0x3f) << 16)
+#define VT0_LF(x) (((x) - 1) & 0xfff)
+
+/* LCD Polarity Control Register */
+#define POL_IVS (1 << 0)
+#define POL_IHS (1 << 1)
+#define POL_ICK (1 << 2)
+#define POL_IDE (1 << 3)
+#define POL_IPWR (1 << 4)
+#define POL_DIV(x) ((((x) - 1) & 0x7f) << 8)
+
+/* LCD Serial Panel Pixel Register */
+#define SPPR_SERIAL (1 << 0)
+#define SPPR_DELTA (1 << 1)
+#define SPPR_CS_RGB (0 << 2)
+#define SPPR_CS_BRG (1 << 2)
+#define SPPR_CS_GBR (2 << 2)
+#define SPPR_LSR (1 << 4)
+#define SPPR_AUO052 (1 << 5)
+
+#endif /* HW_ARM_FTLCDC2XX_H */
diff --git a/hw/arm/ftlcdc200_template.h b/hw/arm/ftlcdc200_template.h
new file mode 100644
index 0000000..f2785fc
--- /dev/null
+++ b/hw/arm/ftlcdc200_template.h
@@ -0,0 +1,439 @@
+/*
+ * Faraday FTLCDC200 Color LCD Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * This code is licensed under the GNU LGPL
+ *
+ * Framebuffer format conversion routines.
+ */
+
+#ifndef ORDER
+
+#if BITS == 8
+#define COPY_PIXEL(to, from) \
+ do { *((to)++) = (from); } while (0)
+#elif BITS == 15 || BITS == 16
+#define COPY_PIXEL(to, from) \
+ do { \
+ *(uint16_t *)to = from;\
+ to += 2;\
+ } while (0)
+#elif BITS == 24
+#define COPY_PIXEL(to, from) \
+ do {\
+ *(to++) = from;\
+ *(to++) = (from) >> 8;\
+ *(to++) = (from) >> 16;\
+ } while (0)
+#elif BITS == 32
+#define COPY_PIXEL(to, from) \
+ do {\
+ *(uint32_t *)to = from;\
+ to += 4;\
+ } while (0)
+#else
+#error unknown bit depth
+#endif
+
+#undef RGB
+#define BORDER bgr
+#define ORDER 0
+#include "ftlcdc200_template.h"
+#define ORDER 1
+#include "ftlcdc200_template.h"
+#define ORDER 2
+#include "ftlcdc200_template.h"
+#undef BORDER
+#define RGB
+#define BORDER rgb
+#define ORDER 0
+#include "ftlcdc200_template.h"
+#define ORDER 1
+#include "ftlcdc200_template.h"
+#define ORDER 2
+#include "ftlcdc200_template.h"
+#undef BORDER
+
+static drawfn glue(ftlcdc200_draw_fn_, BITS)[48] = {
+ glue(ftlcdc200_draw_line1_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line2_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line4_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line8_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line16_555_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line32_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line16_lblp_bgr, BITS),
+ glue(ftlcdc200_draw_line12_lblp_bgr, BITS),
+
+ glue(ftlcdc200_draw_line1_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line2_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line4_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line8_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line16_555_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line32_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line16_bbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line12_bbbp_bgr, BITS),
+
+ glue(ftlcdc200_draw_line1_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line2_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line4_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line8_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line16_555_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line32_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line16_lbbp_bgr, BITS),
+ glue(ftlcdc200_draw_line12_lbbp_bgr, BITS),
+
+ glue(ftlcdc200_draw_line1_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line2_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line4_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line8_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line16_555_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line32_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line16_lblp_rgb, BITS),
+ glue(ftlcdc200_draw_line12_lblp_rgb, BITS),
+
+ glue(ftlcdc200_draw_line1_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line2_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line4_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line8_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line16_555_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line32_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line16_bbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line12_bbbp_rgb, BITS),
+
+ glue(ftlcdc200_draw_line1_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line2_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line4_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line8_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line16_555_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line32_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line16_lbbp_rgb, BITS),
+ glue(ftlcdc200_draw_line12_lbbp_rgb, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+
+#else
+
+#if ORDER == 0
+#define NAME glue(glue(lblp_, BORDER), BITS)
+#ifdef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#elif ORDER == 1
+#define NAME glue(glue(bbbp_, BORDER), BITS)
+#ifndef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#else
+#define SWAP_PIXELS 1
+#define NAME glue(glue(lbbp_, BORDER), BITS)
+#ifdef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#endif
+
+#define FN_2(x, y) FN(x, y) FN(x + 1, y)
+#define FN_4(x, y) FN_2(x, y) FN_2(x + 2, y)
+#define FN_8(y) FN_4(0, y) FN_4(4, y)
+
+static void glue(ftlcdc200_draw_line1_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]);
+#else
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]);
+#endif
+#ifdef SWAP_WORDS
+ FN_8(24)
+ FN_8(16)
+ FN_8(8)
+ FN_8(0)
+#else
+ FN_8(0)
+ FN_8(8)
+ FN_8(16)
+ FN_8(24)
+#endif
+#undef FN
+ width -= 32;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line2_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x) * 2)) & 3]);
+#else
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) * 2 + y)) & 3]);
+#endif
+#ifdef SWAP_WORDS
+ FN_4(0, 24)
+ FN_4(0, 16)
+ FN_4(0, 8)
+ FN_4(0, 0)
+#else
+ FN_4(0, 0)
+ FN_4(0, 8)
+ FN_4(0, 16)
+ FN_4(0, 24)
+#endif
+#undef FN
+ width -= 16;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line4_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x) * 4)) & 0xf]);
+#else
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) * 4 + y)) & 0xf]);
+#endif
+#ifdef SWAP_WORDS
+ FN_2(0, 24)
+ FN_2(0, 16)
+ FN_2(0, 8)
+ FN_2(0, 0)
+#else
+ FN_2(0, 0)
+ FN_2(0, 8)
+ FN_2(0, 16)
+ FN_2(0, 24)
+#endif
+#undef FN
+ width -= 8;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line8_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+ FN(24)
+ FN(16)
+ FN(8)
+ FN(0)
+#else
+ FN(0)
+ FN(8)
+ FN(16)
+ FN(24)
+#endif
+#undef FN
+ width -= 4;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line16_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+#if 0
+ LSB = data & 0x1f;
+ data >>= 5;
+ g = data & 0x3f;
+ data >>= 6;
+ MSB = data & 0x1f;
+ data >>= 5;
+#else
+ LSB = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ MSB = (data & 0x1f) << 3;
+ data >>= 5;
+#endif
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+ LSB = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ MSB = (data & 0x1f) << 3;
+ data >>= 5;
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+#undef MSB
+#undef LSB
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line32_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+#ifndef SWAP_WORDS
+ LSB = data & 0xff;
+ g = (data >> 8) & 0xff;
+ MSB = (data >> 16) & 0xff;
+#else
+ LSB = (data >> 24) & 0xff;
+ g = (data >> 16) & 0xff;
+ MSB = (data >> 8) & 0xff;
+#endif
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+#undef MSB
+#undef LSB
+ width--;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line16_555_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ /* RGB 555 plus an intensity bit (which we ignore) */
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+ LSB = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ MSB = (data & 0x1f) << 3;
+ data >>= 5;
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+ LSB = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ MSB = (data & 0x1f) << 3;
+ data >>= 6;
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+#undef MSB
+#undef LSB
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void glue(ftlcdc200_draw_line12_, NAME)(void *opaque,
+ uint8_t *d,
+ const uint8_t *src,
+ int width,
+ int deststep)
+{
+ /* RGB 444 with 4 bits of zeroes at the top of each halfword */
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+ LSB = (data & 0xf) << 4;
+ data >>= 4;
+ g = (data & 0xf) << 4;
+ data >>= 4;
+ MSB = (data & 0xf) << 4;
+ data >>= 8;
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+ LSB = (data & 0xf) << 4;
+ data >>= 4;
+ g = (data & 0xf) << 4;
+ data >>= 4;
+ MSB = (data & 0xf) << 4;
+ data >>= 8;
+ COPY_PIXEL(d, glue(rgb_to_pixel, BITS)(r, g, b));
+#undef MSB
+#undef LSB
+ width -= 2;
+ src += 4;
+ }
+}
+
+#undef SWAP_PIXELS
+#undef NAME
+#undef SWAP_WORDS
+#undef ORDER
+
+#endif
--
1.7.9.5
- [Qemu-devel] [PATCH v5 11/24] hw/nand.c: bug fix to BUSY/READY status bit, (continued)
- [Qemu-devel] [PATCH v5 11/24] hw/nand.c: bug fix to BUSY/READY status bit, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 14/24] hw/arm: add Faraday FTI2C010 I2C controller support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 18/24] hw/arm: add Faraday FTGMAC100 1Gbps ethernet support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 24/24] hw/arm: add Faraday FTSPI020 SPI flash controller support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 17/24] util: add linux bit ordering reversal functions, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 22/24] hw/arm: add Faraday FTMAC110 10/100Mbps ethernet support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 21/24] hw/arm: add Faraday FTSDC010 MMC/SD controller support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 23/24] hw/arm: add Faraday FTTMR010 timer support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 15/24] hw: add WM8731 codec support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 16/24] hw/arm: add Faraday FTSSP010 multi-function controller support, Kuo-Jung Su, 2013/02/27
- [Qemu-devel] [PATCH v5 19/24] hw/arm: add Faraday FTLCDC200 LCD controller support,
Kuo-Jung Su <=
- [Qemu-devel] [PATCH v5 20/24] hw/arm: add Faraday FTTSC010 touchscreen controller support, Kuo-Jung Su, 2013/02/27