[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform supp
From: |
Kuo-Jung Su |
Subject: |
[Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform support |
Date: |
Fri, 15 Mar 2013 21:13:40 +0800 |
From: Kuo-Jung Su <address@hidden>
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 <address@hidden>
---
hw/arm/Makefile.objs | 3 +
hw/arm/faraday.h | 52 ++++++++++
hw/arm/faraday_a369.c | 98 +++++++++++++++++++
hw/arm/faraday_a369_kpd.c | 231 +++++++++++++++++++++++++++++++++++++++++++++
hw/arm/faraday_a369_scu.c | 182 +++++++++++++++++++++++++++++++++++
hw/arm/faraday_a369_soc.c | 190 +++++++++++++++++++++++++++++++++++++
hw/arm/ftkbc010.h | 44 +++++++++
7 files changed, 800 insertions(+)
create mode 100644 hw/arm/faraday.h
create mode 100644 hw/arm/faraday_a369.c
create mode 100644 hw/arm/faraday_a369_kpd.c
create mode 100644 hw/arm/faraday_a369_scu.c
create mode 100644 hw/arm/faraday_a369_soc.c
create mode 100644 hw/arm/ftkbc010.h
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index f5f7d0e..104e0e7 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -34,3 +34,6 @@ 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 += faraday_a369.o faraday_a369_soc.o faraday_a369_scu.o \
+ faraday_a369_kpd.o
diff --git a/hw/arm/faraday.h b/hw/arm/faraday.h
new file mode 100644
index 0000000..4a9c2ae
--- /dev/null
+++ b/hw/arm/faraday.h
@@ -0,0 +1,52 @@
+/*
+ * Faraday SoC platform support.
+ *
+ * Copyright (c) 2013 Faraday Technology
+ * Written by Kuo-Jung Su <address@hidden>
+ *
+ * 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 {
+ SysBusDevice busdev;
+ hwaddr rom_base;
+ uint64_t rom_size;
+ hwaddr ram_base;
+ uint64_t ram_size;
+ char *cpu_model;
+ ARMCPU *cpu;
+ qemu_irq pic[64];
+ DeviceState *scu; /* System Control Unit */
+ DeviceState *ahbc; /* AHB controller */
+ DeviceState *ddrc; /* DDR controller */
+ 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 */
+
+ uint32_t ahb_slave[32];
+ uint32_t apb_slave[32];
+ bool ahb_remapped;
+ bool ddr_inited;
+ struct arm_boot_info *bi;
+} FaradaySoCState;
+
+/* SoC common APIs */
+#define TYPE_FARADAY_SOC "faraday.soc"
+#define FARADAY_SOC(obj) \
+ OBJECT_CHECK(FaradaySoCState, obj, TYPE_FARADAY_SOC)
+
+#endif
diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
new file mode 100644
index 0000000..3a89a04
--- /dev/null
+++ b/hw/arm/faraday_a369.c
@@ -0,0 +1,98 @@
+/*
+ * Faraday A369 Evalution Board
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * 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 "faraday.h"
+
+/* Board init. */
+
+static void
+a369_board_init(QEMUMachineInitArgs *args)
+{
+ DeviceState *ds;
+ FaradaySoCState *s;
+
+ if (!args->cpu_model) {
+ args->cpu_model = "fa626te";
+ }
+
+ if (!args->ram_size) {
+ args->ram_size = 512 << 20;
+ }
+
+ ds = qdev_create(NULL, TYPE_FARADAY_SOC);
+ qdev_prop_set_string(ds, "cpu_model", args->cpu_model);
+ qdev_prop_set_uint64(ds, "ram_size", args->ram_size);
+ /* 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);
+ qdev_init_nofail(ds);
+
+ s = FARADAY_SOC(ds);
+
+ /* System start-up */
+
+ if (args->kernel_filename) {
+ s->bi = g_new0(struct arm_boot_info, 1);
+
+ s->ddr_inited = true;
+ s->ahb_remapped = true;
+
+ /* Remap AHB slave 4 (ROM) & slave 6 (RAM) */
+ /* 1. Remap RAM to base of ROM */
+ s->ram_base = s->ahb_slave[4] & 0xfff00000;
+ s->ahb_slave[6] = s->ram_base | (s->ahb_slave[6] & 0x000f0000);
+ /* 2. Remap ROM to base of ROM + size of RAM */
+ s->rom_base = s->ram_base
+ + ((1 << extract32(s->ahb_slave[6], 16, 4)) << 20);
+ s->ahb_slave[4] = s->rom_base | (s->ahb_slave[4] & 0x000f0000);
+
+ /* 3. Update ROM Address */
+ sysbus_mmio_map(SYS_BUS_DEVICE(s->rom), 0, s->rom_base);
+
+ /* 4. RAM Address Binding */
+ memory_region_add_subregion(s->as, s->ram_base, s->ram);
+
+ /* 5. Boot Info */
+ s->bi->ram_size = s->ram_size;
+ s->bi->kernel_filename = args->kernel_filename;
+ s->bi->kernel_cmdline = args->kernel_cmdline;
+ s->bi->initrd_filename = args->initrd_filename;
+ s->bi->board_id = 0x3369;
+ arm_load_kernel(s->cpu, s->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/faraday_a369_kpd.c b/hw/arm/faraday_a369_kpd.c
new file mode 100644
index 0000000..7b27725
--- /dev/null
+++ b/hw/arm/faraday_a369_kpd.c
@@ -0,0 +1,231 @@
+/*
+ * Faraday FTKBC010 emulator for A369.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * 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 "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 {
+ SysBusDevice busdev;
+ 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 address@hidden" 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 address@hidden" 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);
+
+ memory_region_init_io(&s->iomem,
+ &mmio_ops,
+ s,
+ TYPE_A369KPD,
+ 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &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/faraday_a369_scu.c b/hw/arm/faraday_a369_scu.c
new file mode 100644
index 0000000..82cc1c1
--- /dev/null
+++ b/hw/arm/faraday_a369_scu.c
@@ -0,0 +1,182 @@
+/*
+ * Faraday A369 SCU
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * 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 {
+ SysBusDevice busdev;
+ 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 address@hidden" 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 address@hidden" 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);
+
+ memory_region_init_io(&s->iomem,
+ &mmio_ops,
+ s,
+ TYPE_A369SCU,
+ 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &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/faraday_a369_soc.c b/hw/arm/faraday_a369_soc.c
new file mode 100644
index 0000000..4e19c7e
--- /dev/null
+++ b/hw/arm/faraday_a369_soc.c
@@ -0,0 +1,190 @@
+/*
+ * Faraday A369 SoC
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * 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 "exec/address-spaces.h"
+
+#include "faraday.h"
+
+static void a369soc_reset(DeviceState *ds)
+{
+ int i;
+ uint64_t size;
+ 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;
+ if (!s->bi) { /* ROM emulation enabled */
+ s->ahb_slave[4] = 0x00080000; /* ROM: base=0x00000000, size=256MB */
+ s->ahb_slave[6] = 0x10090000; /* RAM: base=0x10000000, size=512MB */
+ } else { /* Direct boot */
+ s->ahb_slave[4] = s->rom_base | 0x80000; /* ROM: size=256MB */
+ s->ahb_slave[6] = s->ram_base | 0x90000; /* RAM: 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);
+ }
+
+ /* ROM base = slave4 & 0x000fffff, size = 6KB */
+ s->rom_base = s->ahb_slave[4] & 0xfff00000;
+ s->rom_size = 6 << 10;
+
+ /* RAM base = slave6 & 0x000fffff, size <= (1 << slave6.BIT[19-16]) MB */
+ size = (1 << extract32(s->ahb_slave[6], 16, 4)) << 20;
+ s->ram_base = s->ahb_slave[6] & 0xfff00000;
+ if (!s->ram_size || s->ram_size > size) {
+ s->ram_size = size;
+ }
+}
+
+static void
+a369soc_device_init(FaradaySoCState *s)
+{
+ DriveInfo *dinfo;
+ DeviceState *ds;
+
+ s->as = get_system_memory();
+ s->ram = g_new(MemoryRegion, 1);
+ s->sram = g_new(MemoryRegion, 1);
+
+ /* CPU */
+ s->cpu = cpu_arm_init(!s->cpu_model ? "fa626te" : s->cpu_model);
+ if (!s->cpu) {
+ fprintf(stderr, "a369soc: Unable to find CPU definition\n");
+ abort();
+ }
+
+ /* RAM Init */
+ memory_region_init_ram(s->ram, "a369soc.ram", s->ram_size);
+ vmstate_register_ram_global(s->ram);
+
+ /* Embedded RAM Init */
+ 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(
+ s->rom_base,
+ NULL,
+ "a369soc.rom",
+ s->rom_size,
+ dinfo ? dinfo->bdrv : NULL,
+ 1024, /* 1 KB sector */
+ s->rom_size >> 10, /* 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();
+ }
+
+ /* 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 */
+ ds = sysbus_create_simple("a369.scu", 0x92000000, NULL);
+ s->scu = ds;
+
+ /* ftkbc010 */
+ ds = 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_device_init(s);
+}
+
+static Property a369soc_properties[] = {
+ DEFINE_PROP_STRING("cpu_model", FaradaySoCState, cpu_model),
+ DEFINE_PROP_UINT64("ram_size", FaradaySoCState, ram_size, 0x20000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+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->props = a369soc_properties;
+ 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/arm/ftkbc010.h b/hw/arm/ftkbc010.h
new file mode 100644
index 0000000..43a77ad
--- /dev/null
+++ b/hw/arm/ftkbc010.h
@@ -0,0 +1,44 @@
+/*
+ * Faraday FTKBC010 Keyboard/Keypad Controller
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su <address@hidden>
+ *
+ * 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
- [Qemu-devel] [PATCH v8 00/24] hw/arm: add Faraday A369 SoC platform support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 01/24] target-arm: add Faraday ARMv5TE processors support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 03/24] hw/arm: add FTINTC020 interrupt controller support, Kuo-Jung Su, 2013/03/15
- [Qemu-devel] [PATCH v8 02/24] hw/arm: add Faraday a369 SoC platform support,
Kuo-Jung Su <=
- [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Kuo-Jung Su, 2013/03/15
- Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Peter Crosthwaite, 2013/03/15
- Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Kuo-Jung Su, 2013/03/17
- Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Peter Crosthwaite, 2013/03/17
- Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Kuo-Jung Su, 2013/03/18
- Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Peter Maydell, 2013/03/18
- Re: [Qemu-devel] [PATCH v8 05/24] hw/arm: add FTDDRII030 DDRII controller support, Kuo-Jung Su, 2013/03/19
[Qemu-devel] [PATCH v8 06/24] hw/arm: add FTPWMTMR010 timer support, Kuo-Jung Su, 2013/03/15
[Qemu-devel] [PATCH v8 04/24] hw/arm: add FTAHBC020 AHB controller support, Kuo-Jung Su, 2013/03/15
[Qemu-devel] [PATCH v8 08/24] hw/arm: add FTRTC011 RTC timer support, Kuo-Jung Su, 2013/03/15