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 02/24] hw/arm: add Faraday a369 SoC platform support
Date: Mon, 25 Mar 2013 20:09:38 +0800	[thread overview]
Message-ID: <1364213400-10266-3-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 Faraday A369 EVB is a Faraday SoC platform evalution board used for
Faraday IP functional verification based on the well-known ARM AMBA 2.0
architecture.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/arm/Makefile.objs    |    2 +
 hw/arm/ftplat_a369.c    |   96 +++++++++++++++++++
 hw/arm/ftplat_a369kpd.c |  235 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/arm/ftplat_a369scu.c |  186 +++++++++++++++++++++++++++++++++++++
 hw/arm/ftplat_a369soc.c |  155 +++++++++++++++++++++++++++++++
 hw/faraday.h            |  124 +++++++++++++++++++++++++
 hw/ftkbc010.h           |   44 +++++++++
 7 files changed, 842 insertions(+)
 create mode 100644 hw/arm/ftplat_a369.c
 create mode 100644 hw/arm/ftplat_a369kpd.c
 create mode 100644 hw/arm/ftplat_a369scu.c
 create mode 100644 hw/arm/ftplat_a369soc.c
 create mode 100644 hw/faraday.h
 create mode 100644 hw/ftkbc010.h

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index f5f7d0e..09217c6 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -34,3 +34,5 @@ obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
 obj-y += omap1.o omap2.o
+
+obj-y += ftplat_a369.o ftplat_a369soc.o ftplat_a369scu.o ftplat_a369kpd.o
diff --git a/hw/arm/ftplat_a369.c b/hw/arm/ftplat_a369.c
new file mode 100644
index 0000000..6f00c82
--- /dev/null
+++ b/hw/arm/ftplat_a369.c
@@ -0,0 +1,96 @@
+/*
+ * Faraday A369 Evalution Board
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/i2c.h"
+#include "hw/boards.h"
+#include "hw/ssi.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+
+#include "hw/faraday.h"
+
+/* Board init.  */
+
+static void a369_board_init(QEMUMachineInitArgs *args)
+{
+    ARMCPU *cpu;
+    DeviceState *ds;
+    FaradaySoCState *s;
+
+    if (!args->cpu_model) {
+        args->cpu_model = "fa626te";
+    }
+
+    if (!args->ram_size) {
+        args->ram_size = 512 << 20;
+    }
+
+    /* CPU */
+    cpu = cpu_arm_init(args->cpu_model);
+    if (!cpu) {
+        fprintf(stderr, "a369: Unable to find CPU definition\n");
+        abort();
+    }
+
+    /* SoC */
+    ds = qdev_create(NULL, TYPE_FARADAY_SOC);
+    s = FARADAY_SOC(ds);
+    /* Setup QOM path for the SoC object (i.e. /machine/faraday.soc) */
+    object_property_add_child(qdev_get_machine(),
+                              TYPE_FARADAY_SOC,
+                              OBJECT(ds),
+                              NULL);
+    s->cpu_pic = arm_pic_init_cpu(cpu);
+    s->as  = get_system_memory();
+    s->ram = g_new0(MemoryRegion, 1);
+    memory_region_init_ram(s->ram, TYPE_FARADAY_SOC ".ram", args->ram_size);
+    vmstate_register_ram_global(s->ram);
+    qdev_init_nofail(ds);
+
+    /* System start-up */
+
+    if (args->kernel_filename) {
+        struct arm_boot_info *bi = g_new0(struct arm_boot_info, 1);
+
+        s->ram_boot = true;
+
+        faraday_soc_ram_setup(s, true);
+
+        faraday_soc_ahb_remap(s, true);
+
+        /* Boot Info */
+        bi->ram_size = args->ram_size;
+        bi->kernel_filename = args->kernel_filename;
+        bi->kernel_cmdline = args->kernel_cmdline;
+        bi->initrd_filename = args->initrd_filename;
+        bi->board_id = 0x3369;
+        arm_load_kernel(cpu, bi);
+    } else if (!drive_get(IF_PFLASH, 0, 0)) {
+        fprintf(stderr, "a369: Unable to load ROM image!\n");
+        abort();
+    }
+}
+
+static QEMUMachine a369_machine = {
+    .name = "a369",
+    .desc = "Faraday A369 (fa626te)",
+    .init = a369_board_init,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void a369_machine_init(void)
+{
+    qemu_register_machine(&a369_machine);
+}
+
+machine_init(a369_machine_init);
diff --git a/hw/arm/ftplat_a369kpd.c b/hw/arm/ftplat_a369kpd.c
new file mode 100644
index 0000000..6d42dfa
--- /dev/null
+++ b/hw/arm/ftplat_a369kpd.c
@@ -0,0 +1,235 @@
+/*
+ * Faraday FTKBC010 emulator for A369.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * In A369 EVB, the FTKBC010 is configured as a keypad controller.
+ * It acts like a group of hard wired buttons on the board, each of them
+ * is monitored by the FTKBC010, and coordinated as (x, y).
+ * However there is a pinmux issue in A369 EVB, the Y-axis usually
+ * malfunctioned, so there are only 3 button emulated here.
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+
+#include "hw/ftkbc010.h"
+
+#define CFG_REGSIZE     (0x3c / 4)
+
+/* Key codes */
+#define KEYCODE_ESC             1
+#define KEYCODE_BACKSPACE       14
+#define KEYCODE_ENTER           28
+#define KEYCODE_SPACE           57
+#define KEYCODE_MENU            139    /* Menu (show menu) */
+
+#define TYPE_A369KPD            "a369-kpd"
+
+typedef struct A369KPDState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    /* HW registers */
+    uint32_t regs[CFG_REGSIZE];
+} A369KPDState;
+
+#define A369KPD(obj) \
+    OBJECT_CHECK(A369KPDState, obj, TYPE_A369KPD)
+
+#define KBC_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+static void a369kpd_update_irq(A369KPDState *s)
+{
+    uint32_t ier = 0;
+
+    /* keypad interrupt */
+    ier |= (KBC_REG32(s, REG_CR) & CR_KPDEN) ? ISR_KPDI : 0;
+    /* tx interrupt */
+    ier |= (KBC_REG32(s, REG_CR) & CR_TXIEN) ? ISR_TXI : 0;
+    /* rx interrupt */
+    ier |= (KBC_REG32(s, REG_CR) & CR_RXIEN) ? ISR_RXI : 0;
+
+    qemu_set_irq(s->irq, (ier & KBC_REG32(s, REG_ISR)) ? 1 : 0);
+}
+
+static uint64_t
+a369kpd_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    A369KPDState *s = A369KPD(opaque);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case REG_CR ... REG_ASPR:
+        ret = s->regs[addr / 4];
+        break;
+    case REG_REVR:
+        ret = 0x00010403;  /* rev. = 1.4.3 */
+        break;
+    case REG_FEAR:
+        ret = 0x00000808;  /* 8x8 scan code for keypad */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369kpd: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+a369kpd_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    A369KPDState *s = A369KPD(opaque);
+
+    switch (addr) {
+    case REG_CR:
+        KBC_REG32(s, REG_CR) = (uint32_t)val;
+        /* if ftkbc010 enabled */
+        if (!(KBC_REG32(s, REG_CR) & CR_EN)) {
+            break;
+        }
+        /* if keypad interrupt cleared */
+        if (KBC_REG32(s, REG_CR) & CR_KPDIC) {
+            KBC_REG32(s, REG_CR) &= ~CR_KPDIC;
+            KBC_REG32(s, REG_ISR) &= ~ISR_KPDI;
+        }
+        /* if rx interrupt cleared */
+        if (KBC_REG32(s, REG_CR) & CR_RXICLR) {
+            KBC_REG32(s, REG_CR) &= ~CR_RXICLR;
+            KBC_REG32(s, REG_ISR) &= ~ISR_RXI;
+        }
+        /* if tx interrupt cleared */
+        if (KBC_REG32(s, REG_CR) & CR_TXICLR) {
+            KBC_REG32(s, REG_CR) &= ~CR_TXICLR;
+            KBC_REG32(s, REG_ISR) &= ~ISR_TXI;
+        }
+        a369kpd_update_irq(s);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369kpd: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = a369kpd_mem_read,
+    .write = a369kpd_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void a369kpd_key_event(void *opaque, int scancode)
+{
+    A369KPDState *s = A369KPD(opaque);
+    int x, y, released = 0;
+
+    /* key release from qemu */
+    if (scancode & 0x80) {
+        released = 1;
+    }
+
+    /* strip qemu key release bit */
+    scancode &= ~0x80;
+
+    /* keypad interrupt */
+    if (!released && (KBC_REG32(s, REG_CR) & CR_KPDEN)) {
+        switch (scancode) {
+        case KEYCODE_ESC:
+        case KEYCODE_BACKSPACE:
+            x = 1;
+            break;
+        case KEYCODE_ENTER:
+        case KEYCODE_MENU:
+        case KEYCODE_SPACE:
+            x = 3;
+            break;
+        default:
+            x = 2;    /* KEY_HOME */
+            break;
+        }
+        y = 0;
+        KBC_REG32(s, REG_KPDXR) = ~BIT(x);
+        KBC_REG32(s, REG_KPDYR) = ~BIT(y);
+        KBC_REG32(s, REG_ISR)  |= ISR_KPDI;
+        a369kpd_update_irq(s);
+    }
+}
+
+static void a369kpd_reset(DeviceState *ds)
+{
+    A369KPDState *s = A369KPD(SYS_BUS_DEVICE(ds));
+
+    memset(s->regs, 0, sizeof(s->regs));
+    KBC_REG32(s, REG_KPDXR) = 0xffffffff;
+    KBC_REG32(s, REG_KPDYR) = 0xffffffff;
+
+    qemu_irq_lower(s->irq);
+}
+
+static void a369kpd_realize(DeviceState *dev, Error **errp)
+{
+    A369KPDState *s = A369KPD(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_A369KPD,
+                          0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+
+    qemu_add_kbd_event_handler(a369kpd_key_event, s);
+}
+
+static const VMStateDescription vmstate_ftkbc010 = {
+    .name = TYPE_A369KPD,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, A369KPDState, CFG_REGSIZE),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void a369kpd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_A369KPD;
+    dc->vmsd  = &vmstate_ftkbc010;
+    dc->reset = a369kpd_reset;
+    dc->realize = a369kpd_realize;
+}
+
+static const TypeInfo a369kpd_info = {
+    .name          = TYPE_A369KPD,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(A369KPDState),
+    .class_init    = a369kpd_class_init,
+};
+
+static void a369kpd_register_types(void)
+{
+    type_register_static(&a369kpd_info);
+}
+
+type_init(a369kpd_register_types)
diff --git a/hw/arm/ftplat_a369scu.c b/hw/arm/ftplat_a369scu.c
new file mode 100644
index 0000000..de2e2be
--- /dev/null
+++ b/hw/arm/ftplat_a369scu.c
@@ -0,0 +1,186 @@
+/*
+ * Faraday A369 SCU
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * The system control unit (SCU) is responsible for
+ * power, clock and pinmux management. Since most of
+ * the features are useless to QEMU, only partial clock
+ * and pinmux management are implemented as a set of R/W values.
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+
+#define REG_CHIPID      0x000   /* SoC chip id */
+#define REG_REVISON     0x004   /* SCU revision id */
+#define REG_HWCFG       0x008   /* HW configuration strap */
+#define REG_CPUMFCR     0x00C   /* CPUM (master) freq. control */
+#define REG_SCUCR       0x010   /* SCU control register */
+#define REG_SCUSR       0x014   /* SCU status register */
+#define REG_OSCCR       0x01C   /* OSC control register */
+#define REG_PLL1CR      0x020   /* PLL1 control register */
+#define REG_DLLCR       0x024   /* DLL control register */
+#define REG_SPR(n)      (0x100 + ((n) << 2)) /* Scratchpad register 0 - 15 */
+#define REG_GPINMUX     0x200   /* General PINMUX */
+#define REG_EXTHWCFG    0x204   /* Extended HW configuration strap */
+#define REG_CLKCFG0     0x228   /* Clock configuration 0 */
+#define REG_CLKCFG1     0x22C   /* Clock configuration 1 */
+#define REG_SCER        0x230   /* Special clock enable register */
+#define REG_MFPINMUX0   0x238   /* Multi-function pinmux 0 */
+#define REG_MFPINMUX1   0x23C   /* Multi-function pinmux 1 */
+#define REG_DCSRCR0     0x240   /* Driving cap. & Slew rate control 0 */
+#define REG_DCSRCR1     0x244   /* Driving cap. & Slew rate control 1 */
+#define REG_DCCR        0x254   /* Delay chain control register */
+#define REG_PCR         0x258   /* Power control register */
+
+#define TYPE_A369SCU    "a369-scu"
+#define CFG_REGSIZE     (0x260 / 4)
+
+typedef struct A369SCUState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion iomem;
+
+    /* HW registers */
+    uint32_t regs[CFG_REGSIZE];
+} A369SCUState;
+
+#define A369SCU(obj) \
+    OBJECT_CHECK(A369SCUState, obj, TYPE_A369SCU)
+
+#define SCU_REG32(s, off) \
+    ((s)->regs[(off) / 4])
+
+static uint64_t
+a369scu_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    A369SCUState *s = A369SCU(opaque);
+    uint64_t ret = 0;
+
+    switch (addr) {
+    case 0x000 ... (CFG_REGSIZE - 1) * 4:
+        ret = s->regs[addr / 4];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369scu: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+
+    return ret;
+}
+
+static void
+a369scu_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    A369SCUState *s = A369SCU(opaque);
+
+    switch (addr) {
+    case REG_GPINMUX:
+    case REG_CLKCFG0:
+    case REG_CLKCFG1:
+    case REG_MFPINMUX0:
+    case REG_MFPINMUX1:
+        s->regs[addr / 4] = (uint32_t)val;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "a369scu: undefined memory access@%#" HWADDR_PRIx "\n", addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read  = a369scu_mem_read,
+    .write = a369scu_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void a369scu_reset(DeviceState *ds)
+{
+    A369SCUState *s = A369SCU(SYS_BUS_DEVICE(ds));
+
+    memset(s->regs, 0, sizeof(s->regs));
+
+    SCU_REG32(s, REG_CHIPID)    = 0x00003369; /* A369 */
+    SCU_REG32(s, REG_REVISON)   = 0x00010000; /* Rev. = 1.0.0 */
+    SCU_REG32(s, REG_HWCFG)     = 0x00000c10; /* CPU = 4 * HCLK */
+    SCU_REG32(s, REG_CPUMFCR)   = 0x00000230; /* CPU = 4 * HCLK */
+    SCU_REG32(s, REG_SCUCR)     = 0x00000083; /* no low power detect */
+    SCU_REG32(s, REG_SCUSR)     = 0x00000100; /* CPU freq. stable */
+    SCU_REG32(s, REG_OSCCR)     = 0x00000003; /* OSCH disabled */
+    SCU_REG32(s, REG_PLL1CR)    = 0x20010003; /* PLL_NS = 32 */
+    SCU_REG32(s, REG_DLLCR)     = 0x00000003; /* DLL enabled & stable */
+    SCU_REG32(s, REG_GPINMUX)   = 0x00001078; /* Pinmux */
+    SCU_REG32(s, REG_EXTHWCFG)  = 0x00001cc8; /* NAND flash boot */
+    SCU_REG32(s, REG_CLKCFG0)   = 0x26877330; /* LCD = HCLK */
+    SCU_REG32(s, REG_CLKCFG1)   = 0x000a0a0a; /* SD = HCLK, SPI=PCLK */
+    SCU_REG32(s, REG_SCER)      = 0x00003fff; /* All clock enabled */
+    SCU_REG32(s, REG_MFPINMUX0) = 0x00000241; /* Pinmux */
+    SCU_REG32(s, REG_MFPINMUX1) = 0x00000000; /* Pinmux */
+    SCU_REG32(s, REG_DCSRCR0)   = 0x11111111; /* Slow slew rate */
+    SCU_REG32(s, REG_DCSRCR1)   = 0x11111111; /* Slow slew rate */
+    SCU_REG32(s, REG_DCCR)      = 0x00000303; /* All delay chain = 3 */
+    SCU_REG32(s, REG_PCR)       = 0x8000007f; /* High performance mode */
+}
+
+static void a369scu_realize(DeviceState *dev, Error **errp)
+{
+    A369SCUState *s = A369SCU(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem,
+                          &mmio_ops,
+                          s,
+                          TYPE_A369SCU,
+                          0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription vmstate_a369scu = {
+    .name = TYPE_A369SCU,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, A369SCUState, CFG_REGSIZE),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void a369scu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_A369SCU;
+    dc->vmsd  = &vmstate_a369scu;
+    dc->reset = a369scu_reset;
+    dc->realize = a369scu_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo a369scu_info = {
+    .name          = TYPE_A369SCU,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(A369SCUState),
+    .class_init    = a369scu_class_init,
+};
+
+static void a369scu_register_types(void)
+{
+    type_register_static(&a369scu_info);
+}
+
+type_init(a369scu_register_types)
diff --git a/hw/arm/ftplat_a369soc.c b/hw/arm/ftplat_a369soc.c
new file mode 100644
index 0000000..624b549
--- /dev/null
+++ b/hw/arm/ftplat_a369soc.c
@@ -0,0 +1,155 @@
+/*
+ * Faraday A369 SoC
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/i2c.h"
+#include "hw/boards.h"
+#include "hw/flash.h"
+#include "hw/serial.h"
+#include "hw/ssi.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
+
+#include "hw/faraday.h"
+
+static void a369soc_reset(DeviceState *ds)
+{
+    int i;
+    FaradaySoCState *s = FARADAY_SOC(SYS_BUS_DEVICE(ds));
+
+    /* AHB slave base & window configuration */
+    memset(s->ahb_slave, 0, sizeof(s->ahb_slave));
+    s->ahb_slave[0] = 0x94050000;
+    s->ahb_slave[1] = 0x96040000;
+    s->ahb_slave[2] = 0x90f00000;
+    s->ahb_slave[3] = 0x92050000; /* APB: base=0x92000000, size=32MB */
+    s->ahb_slave[5] = 0xc0080000;
+    s->ahb_slave[4] = 0x00080000; /* ROM: base=0x00000000, size=256MB */
+    s->ahb_slave[6] = 0x10090000; /* RAM: base=0x10000000, size=512MB */
+    for (i = 0; i < 15; ++i) {
+        s->ahb_slave[7 + i] = 0x90000000 + (i << 20);
+    }
+    s->ahb_slave[22] = 0x40080000;
+    s->ahb_slave[23] = 0x60080000;
+    s->ahb_slave[24] = 0xa0000000; /* SRAM: base=0xA0000000, size=1MB */
+
+    /* APB slave base & window configuration */
+    memset(s->apb_slave, 0, sizeof(s->apb_slave));
+    for (i = 0; i < 18; ++i) {
+        s->apb_slave[i] = 0x12000000 + (i << 20);
+    }
+}
+
+static void a369soc_chip_init(FaradaySoCState *s)
+{
+    DriveInfo *dinfo;
+
+    /* Remappable Memory Region Init */
+    s->rmr = g_new0(MemoryRegion, 1);
+    memory_region_init(s->rmr, "a369soc.rmr", 0x80000000);
+    memory_region_add_subregion(s->as, 0x00000000, s->rmr);
+
+    /* Embedded RAM Init */
+    s->sram = g_new0(MemoryRegion, 1);
+    memory_region_init_ram(s->sram, "a369soc.sram", 0x4000);
+    vmstate_register_ram_global(s->sram);
+    memory_region_add_subregion(s->as, 0xA0000000, s->sram);
+
+    /* Embedded ROM Init (Emulated with a parallel NOR flash) */
+    dinfo = drive_get_next(IF_PFLASH);
+    s->rom = pflash_cfi01_register(
+                    (hwaddr)-1,
+                    NULL,
+                    "a369soc.rom",
+                    6 << 10,
+                    dinfo ? dinfo->bdrv : NULL,
+                    1024,               /* 1 KB sector */
+                    6,                  /* sectors per chip */
+                    4,                  /* 32 bits */
+                    0, 0, 0, 0,         /* id */
+                    0                   /* Little Endian */);
+    if (!s->rom) {
+        fprintf(stderr, "a369soc: Unable to init ROM device.\n");
+        abort();
+    }
+    memory_region_add_subregion(s->rmr, s->rom_base,
+                sysbus_mmio_get_region(SYS_BUS_DEVICE(s->rom), 0));
+
+    /* Serial (FTUART010 which is 16550A compatible) */
+    if (serial_hds[0]) {
+        serial_mm_init(s->as,
+                       0x92b00000,
+                       2,
+                       s->pic[53],
+                       18432000,
+                       serial_hds[0],
+                       DEVICE_LITTLE_ENDIAN);
+    }
+    if (serial_hds[1]) {
+        serial_mm_init(s->as,
+                       0x92c00000,
+                       2,
+                       s->pic[54],
+                       18432000,
+                       serial_hds[1],
+                       DEVICE_LITTLE_ENDIAN);
+    }
+
+    /* ftscu010 */
+    sysbus_create_simple("a369-scu", 0x92000000, NULL);
+
+    /* ftkbc010 */
+    sysbus_create_simple("a369-kpd", 0x92f00000, s->pic[21]);
+}
+
+static void a369soc_realize(DeviceState *dev, Error **errp)
+{
+    FaradaySoCState *s = FARADAY_SOC(dev);
+
+    a369soc_reset(dev);
+    a369soc_chip_init(s);
+}
+
+static const VMStateDescription vmstate_a369soc = {
+    .name = TYPE_FARADAY_SOC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void a369soc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc  = TYPE_FARADAY_SOC;
+    dc->vmsd  = &vmstate_a369soc;
+    dc->reset = a369soc_reset;
+    dc->realize = a369soc_realize;
+    dc->no_user = 1;
+}
+
+static const TypeInfo a369soc_info = {
+    .name          = TYPE_FARADAY_SOC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(FaradaySoCState),
+    .class_init    = a369soc_class_init,
+};
+
+static void a369soc_register_types(void)
+{
+    type_register_static(&a369soc_info);
+}
+
+type_init(a369soc_register_types)
diff --git a/hw/faraday.h b/hw/faraday.h
new file mode 100644
index 0000000..7373ba0
--- /dev/null
+++ b/hw/faraday.h
@@ -0,0 +1,124 @@
+/*
+ * Faraday SoC platform support.
+ *
+ * Copyright (c) 2013 Faraday Technology
+ * Written by Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#ifndef HW_ARM_FARADAY_H
+#define HW_ARM_FARADAY_H
+
+#include "hw/flash.h"
+#include "qemu/bitops.h"
+
+typedef struct FaradaySoCState {
+    /*< private >*/
+    SysBusDevice parent;
+
+    /*< public >*/
+    bool         ram_boot;
+    uint32_t     ahb_slave[32];
+    uint32_t     apb_slave[32];
+
+    hwaddr       rom_base;
+    hwaddr       ram_base;
+    qemu_irq     *cpu_pic;
+    qemu_irq     *pic;
+    DeviceState  *hdma[2];  /* AHB DMA */
+    DeviceState  *pdma[1];  /* APB DMA */
+    DeviceState  *spi[2];   /* Generic SPI bus */
+    DeviceState  *spi_fl[2];/* Dedicated SPI bus for flash memory */
+    DeviceState  *i2c[2];   /* Generic I2C bus */
+    DeviceState  *i2s[2];   /* Generic I2S bus */
+    DeviceState  *nandc[2]; /* NAND flash controller */
+
+    MemoryRegion *as;       /* address space */
+    MemoryRegion *ram;      /* external sdram */
+    pflash_t     *rom;      /* on-chip rom */
+    MemoryRegion *sram;     /* on-chip static ram */
+
+    MemoryRegion *rmr;      /* remappable memory region */
+    MemoryRegion *ram_visible;  /* ram alias controlled by DDR controller */
+} FaradaySoCState;
+
+/* SoC common APIs */
+#define TYPE_FARADAY_SOC    "faraday-soc"
+#define FARADAY_SOC(obj) \
+    OBJECT_CHECK(FaradaySoCState, obj, TYPE_FARADAY_SOC)
+
+static inline void faraday_soc_ram_setup(FaradaySoCState *s, bool visible)
+{
+    uint64_t size, ram_size = 0;
+
+    if (!s->as || !s->ram) {
+        return;
+    }
+
+    /* RAM size <= (1 << slave6.BIT[19-16]) MB */
+    size = (1 << extract32(s->ahb_slave[6], 16, 4)) << 20;
+    if (!ram_size || ram_size > size) {
+        ram_size = size;
+    }
+
+    if (visible) {
+        if (!s->ram_visible) {
+            s->ram_visible = g_new0(MemoryRegion, 1);
+            memory_region_init_alias(s->ram_visible,
+                                     TYPE_FARADAY_SOC ".ram_visible",
+                                     s->ram,
+                                     0,
+                                     ram_size);
+        }
+        memory_region_add_subregion(s->rmr, s->ram_base, s->ram_visible);
+    } else {
+        if (!s->ram_boot && s->ram_visible) {
+            memory_region_del_subregion(s->rmr, s->ram_visible);
+            g_free(s->ram_visible);
+            s->ram_visible = NULL;
+        }
+    }
+}
+
+/* Remap AHB slave 4 (ROM) & slave 6 (RAM) */
+static inline void faraday_soc_ahb_remap(FaradaySoCState *s, bool active)
+{
+    if (!s->ahb_slave[4] || !s->ahb_slave[6]) {
+        fprintf(stderr,
+                "faraday_soc_ahb_remap: "
+                "AHB slave 4 or 6 is not yet initialized!\n");
+        abort();
+    }
+
+    if (!active && s->ram_boot) {
+        return;
+    }
+
+    if (active) {
+        /* Remap RAM to base of ROM */
+        s->ram_base = s->ahb_slave[4] & 0xfff00000;
+        /* Remap ROM to base of ROM + size of RAM */
+        s->rom_base = s->ram_base
+                    + ((1 << extract32(s->ahb_slave[6], 16, 4)) << 20);
+    } else {
+        s->rom_base = s->ahb_slave[4] & 0xfff00000;
+        s->ram_base = s->ahb_slave[6] & 0xfff00000;
+    }
+
+    /* Update ROM/RAM Address */
+    if (s->as && s->ram_visible) {
+        memory_region_del_subregion(s->rmr, s->ram_visible);
+    }
+
+    if (s->rom) {
+        MemoryRegion *mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(s->rom), 0);
+        memory_region_del_subregion(s->rmr, mr);
+        memory_region_add_subregion(s->rmr, s->rom_base, mr);
+    }
+
+    if (s->as && s->ram_visible) {
+        memory_region_add_subregion(s->rmr, s->ram_base, s->ram_visible);
+    }
+}
+
+#endif
diff --git a/hw/ftkbc010.h b/hw/ftkbc010.h
new file mode 100644
index 0000000..43a77ad
--- /dev/null
+++ b/hw/ftkbc010.h
@@ -0,0 +1,44 @@
+/*
+ * Faraday FTKBC010 Keyboard/Keypad Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under GNU GPL v2+
+ */
+#ifndef HW_ARM_FTKBC010_H
+#define HW_ARM_FTKBC010_H
+
+#include "qemu/bitops.h"
+
+#define REG_CR      0x00    /* control register */
+#define REG_SRDR    0x04    /* sample rate division register */
+#define REG_RSCR    0x08    /* request to send counter register */
+#define REG_SR      0x0C    /* status register */
+#define REG_ISR     0x10    /* interrupt status register */
+#define REG_KBDRR   0x14    /* keyboard receive register */
+#define REG_KBDTR   0x18    /* keyboard transmit register */
+#define REG_IMR     0x1C    /* interrupt mask register */
+#define REG_KPDXR   0x30    /* keypad X-Axis register */
+#define REG_KPDYR   0x34    /* keypad Y-Axis register */
+#define REG_ASPR    0x38    /* auto-scan period register */
+#define REG_REVR    0x50    /* revision register */
+#define REG_FEAR    0x54    /* feature register */
+
+#define CR_KPDIC    BIT(10) /* Write 1 to clear Keypad interupt */
+#define CR_KPDAS    BIT(9)  /* Keypad audo-scan enabled */
+#define CR_KPDEN    BIT(8)  /* Keypad function enabled */
+#define CR_RXICLR   BIT(7)  /* Write 1 to clear Keyboard/Mouse Rx interrupt */
+#define CR_TXICLR   BIT(6)  /* Write 1 to clear Keyboard/Mouse Tx interrupt */
+#define CR_NOLC     BIT(5)  /* No line control bit */
+#define CR_RXIEN    BIT(4)  /* Keyboard/Mouse Rx interrupt enabled */
+#define CR_TXIEN    BIT(3)  /* Keyboard/Mouse Tx interrupt enabled */
+#define CR_EN       BIT(2)  /* Chip enabled */
+#define CR_DATDN    BIT(1)  /* Data disabled */
+#define CR_CLKDN    BIT(0)  /* Clock disabled */
+
+#define ISR_KPDI    BIT(2)  /* Keypad interupt */
+#define ISR_TXI     BIT(1)  /* Keyboard/Mouse Tx interrupt enabled */
+#define ISR_RXI     BIT(0)  /* Keyboard/Mouse Rx interrupt enabled */
+
+#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 ` Kuo-Jung Su [this message]
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 ` [Qemu-devel] [PATCH v9 19/24] hw/arm: add FTLCDC200 LCD controller support Kuo-Jung Su
2013-03-25 12:09 ` [Qemu-devel] [PATCH v9 20/24] hw/arm: add FTTSC010 touchscreen " 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-3-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.