All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kuo-Jung Su <dantesu@gmail.com>
To: qemu-devel@nongnu.org
Cc: Peter Maydell <peter.maydell@linaro.org>,
	i.mitsyanko@samsung.com, Blue Swirl <blauwirbel@gmail.com>,
	Paul Brook <paul@codesourcery.com>,
	Kuo-Jung Su <dantesu@faraday-tech.com>,
	Andreas <afaerber@suse.de>,
	fred.konrad@greensocs.com
Subject: [Qemu-devel] [PATCH v9 19/24] hw/arm: add FTLCDC200 LCD controller support
Date: Mon, 25 Mar 2013 20:09:55 +0800	[thread overview]
Message-ID: <1364213400-10266-20-git-send-email-dantesu@gmail.com> (raw)
In-Reply-To: <1364213400-10266-1-git-send-email-dantesu@gmail.com>

From: Kuo-Jung Su <dantesu@faraday-tech.com>

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 <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs    |    2 +-
 hw/arm/ftplat_a369soc.c |   10 +
 hw/ftlcdc200.c          |  516 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/ftlcdc200.h          |  110 ++++++++++
 hw/ftlcdc200_template.h |  439 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1076 insertions(+), 1 deletion(-)
 create mode 100644 hw/ftlcdc200.c
 create mode 100644 hw/ftlcdc200.h
 create mode 100644 hw/ftlcdc200_template.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 62c823d..f6b947e 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -26,7 +26,7 @@ obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
 obj-$(CONFIG_KVM) += kvm/arm_gic.o
 obj-y += ftintc020.o ftahbc020.o ftddrii030.o ftpwmtmr010.o ftwdt010.o \
                 ftrtc011.o ftdmac020.o ftapbbrg020.o ftnandc021.o fti2c010.o \
-                ftssp010.o ftgmac100.o
+                ftssp010.o ftgmac100.o ftlcdc200.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/arm/ftplat_a369soc.c b/hw/arm/ftplat_a369soc.c
index 622b1db..cdc6d4a 100644
--- a/hw/arm/ftplat_a369soc.c
+++ b/hw/arm/ftplat_a369soc.c
@@ -228,6 +228,16 @@ static void a369soc_chip_init(FaradaySoCState *s)
     if (nb_nics > 0) {
         ftgmac100_init(&nd_table[0], 0x90c00000, s->pic[32]);
     }
+
+    /* ftlcdc200 */
+    sysbus_create_varargs("ftlcdc200",
+                          0x94a00000,
+                          s->pic[0],  /* ALL (NC in A369) */
+                          s->pic[25], /* VSTATUS */
+                          s->pic[24], /* Base Address Update */
+                          s->pic[23], /* FIFO Under-Run */
+                          s->pic[22], /* AHB Bus Error */
+                          NULL);
 }
 
 static void a369soc_realize(DeviceState *dev, Error **errp)
diff --git a/hw/ftlcdc200.c b/hw/ftlcdc200.c
new file mode 100644
index 0000000..2e25372
--- /dev/null
+++ b/hw/ftlcdc200.c
@@ -0,0 +1,516 @@
+/*
+ * Faraday FTLCDC200 Color LCD Controller
+ *
+ * base is pl110.c
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * 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 "qemu/bitops.h"
+#include "hw/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;
+    QemuConsole *con;
+
+    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);
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    drawfn *fntable;
+    drawfn fn;
+    int dest_width;
+    int src_width;
+    int bpp_offset;
+    int first;
+    int last;
+
+    if (!ftlcdc200_enabled(s)) {
+        return;
+    }
+
+    switch (surface_bits_per_pixel(surface)) {
+    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:
+        fprintf(stderr, "ftlcdc200: Bad color depth\n");
+        abort();
+    }
+
+    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(surface,
+                               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->con, 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->con, s->cols, s->rows);
+    }
+}
+
+static void ftlcdc200_update_palette(Ftlcdc200State *s, int n)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    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 (surface_bits_per_pixel(surface)) {
+        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->con, 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];
+    /* we don't care */
+    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 access@%#" HWADDR_PRIx "\n", 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->con, 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->con, 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 access@%#" HWADDR_PRIx "\n", 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)
+{
+    Ftlcdc200State *s = FTLCDC200(SYS_BUS_DEVICE(ds));
+
+    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 void ftlcdc200_realize(DeviceState *dev, Error **errp)
+{
+    Ftlcdc200State *s = FTLCDC200(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_FTLCDC200,
+                          0x10000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq[IRQ_ALL]);
+    sysbus_init_irq(sbd, &s->irq[IRQ_VSTATUS]);
+    sysbus_init_irq(sbd, &s->irq[IRQ_BASEUPT]);
+    sysbus_init_irq(sbd, &s->irq[IRQ_FIFOUR]);
+    sysbus_init_irq(sbd, &s->irq[IRQ_BUSERR]);
+    s->con = graphic_console_init(ftlcdc200_update_display,
+                                  ftlcdc200_invalidate_display,
+                                  NULL, NULL, s);
+}
+
+static void ftlcdc200_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset   = ftlcdc200_reset;
+    dc->vmsd    = &vmstate_ftlcdc200;
+    dc->realize = ftlcdc200_realize;
+    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/ftlcdc200.h b/hw/ftlcdc200.h
new file mode 100644
index 0000000..53917e1
--- /dev/null
+++ b/hw/ftlcdc200.h
@@ -0,0 +1,110 @@
+/*
+ * Faraday FTLCDC200 Color LCD Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * 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/ftlcdc200_template.h b/hw/ftlcdc200_template.h
new file mode 100644
index 0000000..f2785fc
--- /dev/null
+++ b/hw/ftlcdc200_template.h
@@ -0,0 +1,439 @@
+/*
+ * Faraday FTLCDC200 Color LCD Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * 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

  parent reply	other threads:[~2013-03-25 12:11 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-25 12:09 [Qemu-devel] [PATCH v9 00/24] hw/arm: add Faraday A369 SoC platform support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 01/24] target-arm: add Faraday ARMv5TE processors support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 02/24] hw/arm: add Faraday a369 SoC platform support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 03/24] hw/arm: add FTINTC020 interrupt controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 04/24] hw/arm: add FTAHBC020 AHB " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 05/24] hw/arm: add FTDDRII030 DDRII " Kuo-Jung Su
2013-03-28  0:09   ` Peter Crosthwaite
2013-03-28  3:24     ` Kuo-Jung Su
2013-03-28  3:58       ` Peter Crosthwaite
2013-03-28  5:28         ` Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 06/24] hw/arm: add FTPWMTMR010 timer support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 07/24] hw/arm: add FTWDT010 watchdog " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 08/24] hw/arm: add FTRTC011 RTC " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 09/24] tests: add QTest for FTRTC011 Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 10/24] hw/arm: add FTDMAC020 AHB DMA support Kuo-Jung Su
2013-03-29  0:22   ` Peter Crosthwaite
2013-03-29  7:23     ` Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 11/24] hw/arm: add FTAPBBRG020 APB " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 12/24] hw/arm: add FTNANDC021 nand flash controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 13/24] hw/arm: add FTI2C010 I2C " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 14/24] hw: Add AudioCodecClass for wm87xx audio class abstration Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 15/24] hw: add WM8731 audio codec support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 16/24] The FTSSP010 is a multi-function synchronous serial port interface controller which supports SSP, SPI, I2S, AC97 and SPDIF Kuo-Jung Su
2013-03-31  2:39   ` Peter Crosthwaite
2013-04-01  1:18     ` Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 17/24] qemu/bitops.h: add the bit ordering reversal functions Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 18/24] hw/arm: add FTGMAC100 1Gbps ethernet support Kuo-Jung Su
2013-03-25 12:09 ` Kuo-Jung Su [this message]
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 20/24] hw/arm: add FTTSC010 touchscreen controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 21/24] hw/arm: add FTSDC010 MMC/SD " Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 22/24] hw/arm: add FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 23/24] hw/arm: add FTTMR010 timer support Kuo-Jung Su
2013-03-25 12:10 ` [Qemu-devel] [PATCH v9 24/24] hw/arm: add FTSPI020 SPI flash controller support Kuo-Jung Su
2013-03-29  0:02   ` Peter Crosthwaite
2013-03-29  7:15     ` Kuo-Jung Su

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1364213400-10266-20-git-send-email-dantesu@gmail.com \
    --to=dantesu@gmail.com \
    --cc=afaerber@suse.de \
    --cc=blauwirbel@gmail.com \
    --cc=dantesu@faraday-tech.com \
    --cc=fred.konrad@greensocs.com \
    --cc=i.mitsyanko@samsung.com \
    --cc=paul@codesourcery.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.