[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v5 02/24] hw/arm: add Faraday a369 SoC platform
From: |
Kuo-Jung Su |
Subject: |
Re: [Qemu-devel] [PATCH v5 02/24] hw/arm: add Faraday a369 SoC platform support |
Date: |
Mon, 4 Mar 2013 14:06:34 +0800 |
2013/3/2 Igor Mitsyanko <address@hidden>:
> Hi, Kuo-Jung
>
> On 02/27/2013 11:15 AM, Kuo-Jung Su wrote:
>> 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 | 4 +
>> hw/arm/faraday.h | 65 +++++++++++++
>> hw/arm/faraday_a369.c | 94 ++++++++++++++++++
>> hw/arm/faraday_a369_kpd.c | 237
>> +++++++++++++++++++++++++++++++++++++++++++++
>> hw/arm/faraday_a369_scu.c | 187 +++++++++++++++++++++++++++++++++++
>> hw/arm/faraday_a369_soc.c | 197 +++++++++++++++++++++++++++++++++++++
>> hw/arm/ftkbc010.h | 42 ++++++++
>> 7 files changed, 826 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 6d049e7..f6fd60d 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -33,3 +33,7 @@ obj-y += kzm.o
>> obj-$(CONFIG_FDT) += ../device_tree.o
>>
>> obj-y := $(addprefix ../,$(obj-y))
>> +obj-y += faraday_a369.o \
>> + faraday_a369_soc.o \
>> + faraday_a369_scu.o \
>> + faraday_a369_kpd.o
>
> Seems that convention for this file is to shift to the next line only
> after current line length is > 80 characters.
>
Got it, thanks
>> diff --git a/hw/arm/faraday.h b/hw/arm/faraday.h
>> new file mode 100644
>> index 0000000..d6ed860
>> --- /dev/null
>> +++ b/hw/arm/faraday.h
>> @@ -0,0 +1,65 @@
>> +/*
>> + * 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"
>> +
>> +#ifdef DEBUG_FARADAY
>> +#define DPRINTF(fmt, ...) \
>> + do { printf("faraday: " fmt , ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF(fmt, ...) \
>> + do { } while (0)
>> +#endif
>
> Recently there was a discussions over what kind of debug format to use,
> you can see an outcome here
> http://thread.gmane.org/gmane.comp.emulators.qemu/195996/focus=196975
>
Got it, thanks
>> +
>> +typedef struct FaradaySoCState {
>> + SysBusDevice busdev;
>> + hwaddr rom_base;
>> + uint64_t rom_size;
>> + hwaddr ram_base;
>> + uint64_t ram_size;
>> + char *cpu_model;
>> + ARMCPU *cpu;
>> + 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];
>> + DeviceState *i2c[2];
>> + DeviceState *i2s[2];
>> + DeviceState *codec; /* Audio codec */
>> + void (*codec_out)(void *, uint32_t);
>> + uint32_t (*codec_in)(void *);
>> +
>> + MemoryRegion *as;
>> + MemoryRegion *ram;
>> + pflash_t *rom;
>> + MemoryRegion *sram;
>> +
>> + void *priv;
>> +
>> + 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"
>
> Using "/" here will break qom-list command because "/" symbol is a
> delimiter in a QOM canonical path.
>
Got it, thanks
>> +#define FARADAY_SOC(obj) \
>> + OBJECT_CHECK(FaradaySoCState, obj, TYPE_FARADAY_SOC)
>> +#define FARADAY_SOC_GET_CORE() \
>> + FARADAY_SOC(object_resolve_path_component(qdev_get_machine(), \
>> + TYPE_FARADAY_SOC))
>> +
>> +#endif
>> diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
>> new file mode 100644
>> index 0000000..0b6201a
>> --- /dev/null
>> +++ b/hw/arm/faraday_a369.c
>> @@ -0,0 +1,94 @@
>> +/*
>> + * 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 "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);
>> +
>> + 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)) {
>> + hw_error("a369: failed to load ROM image!\n");
>> + exit(1);
>> + }
>> +}
>> +
>> +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..967ada6
>> --- /dev/null
>> +++ b/hw/arm/faraday_a369_kpd.c
>> @@ -0,0 +1,237 @@
>> +/*
>> + * Faraday FTKBC010 emulator for A369.
>> + *
>> + * Copyright (c) 2012 Faraday Technology
>> + * Written by Dante Su <address@hidden>
>> + *
>> + * The FTKBC010 is configured as a keypad controller for A369.
>> + * It's a group of hard wired buttons on the board, each of them
>> + * is monitored by the FTKBC010, and coordinated as (x, y).
>> + * However in A369, there is a pinmux issue that 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 "faraday.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_FTKBC010 "a369.keypad"
>> +
>> +typedef struct Ftkbc010State {
>> + SysBusDevice busdev;
>> + MemoryRegion iomem;
>> + qemu_irq irq;
>> +
>> + /* HW registers */
>> + uint32_t regs[CFG_REGSIZE];
>> +} Ftkbc010State;
>> +
>> +#define FTKBC010(obj) \
>> + OBJECT_CHECK(Ftkbc010State, obj, TYPE_FTKBC010)
>> +
>> +#define KBC_REG32(s, off) \
>> + *(uint32_t *)((uint8_t *)(s)->regs + (off))
>> +
>> +static void ftkbc010_update_irq(Ftkbc010State *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 ftkbc010_mem_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> + Ftkbc010State *s = FTKBC010(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", addr);
>
> This doesn't compile on 64-bit machines, you should replace llx with
> HWADDR_PRIx.
>
Got it, thanks
>> + break;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +static void ftkbc010_mem_write(void *opaque,
>> + hwaddr addr,
>> + uint64_t val,
>> + unsigned size)
>> +{
>> + Ftkbc010State *s = FTKBC010(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;
>> + }
>> + ftkbc010_update_irq(s);
>> + break;
>> + default:
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "a369kpd: undefined memory address@hidden", addr);
>
> HWADDR_PRIx
>
>> + break;
>> + }
>> +}
>> +
>> +static const MemoryRegionOps mmio_ops = {
>> + .read = ftkbc010_mem_read,
>> + .write = ftkbc010_mem_write,
>> + .endianness = DEVICE_LITTLE_ENDIAN,
>> + .valid = {
>> + .min_access_size = 4,
>> + .max_access_size = 4,
>> + }
>> +};
>> +
>> +static void ftkbc010_key_event(void *opaque, int scancode)
>> +{
>> + Ftkbc010State *s = FTKBC010(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;
>> + ftkbc010_update_irq(s);
>> + }
>> +}
>> +
>> +static void ftkbc010_reset(DeviceState *ds)
>> +{
>> + SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
>> + Ftkbc010State *s = FTKBC010(FROM_SYSBUS(Ftkbc010State, busdev));
>
> You can drop FROM_SYSBUS() completely, here and in several other places.
>
Got it, thanks
>> +
>> + 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 int ftkbc010_init(SysBusDevice *dev)
>> +{
>> + Ftkbc010State *s = FTKBC010(FROM_SYSBUS(Ftkbc010State, dev));
>> +
>> + memory_region_init_io(&s->iomem,
>> + &mmio_ops,
>> + s,
>> + TYPE_FTKBC010,
>> + 0x1000);
>> + sysbus_init_mmio(dev, &s->iomem);
>> + sysbus_init_irq(dev, &s->irq);
>> +
>> + qemu_add_kbd_event_handler(ftkbc010_key_event, s);
>> +
>> + return 0;
>> +}
>> +
>> +static const VMStateDescription vmstate_ftkbc010 = {
>> + .name = TYPE_FTKBC010,
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .minimum_version_id_old = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT32_ARRAY(regs, Ftkbc010State, CFG_REGSIZE),
>> + VMSTATE_END_OF_LIST(),
>> + }
>> +};
>> +
>> +static void ftkbc010_class_init(ObjectClass *klass, void *data)
>> +{
>> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + k->init = ftkbc010_init;
>> + dc->desc = TYPE_FTKBC010;
>> + dc->vmsd = &vmstate_ftkbc010;
>> + dc->reset = ftkbc010_reset;
>> +}
>> +
>> +static const TypeInfo ftkbc010_info = {
>> + .name = TYPE_FTKBC010,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(Ftkbc010State),
>> + .class_init = ftkbc010_class_init,
>> +};
>> +
>> +static void ftkbc010_register_types(void)
>> +{
>> + type_register_static(&ftkbc010_info);
>> +}
>> +
>> +type_init(ftkbc010_register_types)
>> diff --git a/hw/arm/faraday_a369_scu.c b/hw/arm/faraday_a369_scu.c
>> new file mode 100644
>> index 0000000..4c779ab
>> --- /dev/null
>> +++ b/hw/arm/faraday_a369_scu.c
>> @@ -0,0 +1,187 @@
>> +/*
>> + * 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"
>> +
>> +#include "faraday.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) \
>> + *(uint32_t *)((uint8_t *)(s)->regs + (off))
>> +
>> +static uint64_t
>> +a369scu_mem_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> + A369SCUState *s = A369SCU(opaque);
>> + uint64_t ret = 0;
>> +
>> + switch (addr) {
>> + case 0x000 ... 0x25C:
>> + ret = s->regs[addr / 4];
>> + break;
>> + default:
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "a369scu: undefined memory address@hidden", addr);
>
> HWADDR_PRIx
>
>> + 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", addr);
>
> HWADDR_PRIx
>
>> + 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)
>> +{
>> + SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
>> + A369SCUState *s = A369SCU(FROM_SYSBUS(A369SCUState, busdev));
>> +
>> + 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 int a369scu_init(SysBusDevice *dev)
>> +{
>> + A369SCUState *s = A369SCU(FROM_SYSBUS(A369SCUState, dev));
>> +
>> + memory_region_init_io(&s->iomem,
>> + &mmio_ops,
>> + s,
>> + TYPE_A369SCU,
>> + 0x1000);
>> + sysbus_init_mmio(dev, &s->iomem);
>> + return 0;
>> +}
>> +
>> +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)
>> +{
>> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + k->init = a369scu_init;
>> + dc->desc = TYPE_A369SCU;
>> + dc->vmsd = &vmstate_a369scu;
>> + dc->reset = a369scu_reset;
>> + 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..0372868
>> --- /dev/null
>> +++ b/hw/arm/faraday_a369_soc.c
>> @@ -0,0 +1,197 @@
>> +/*
>> + * 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;
>> + SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
>> + FaradaySoCState *s = FARADAY_SOC(FROM_SYSBUS(FaradaySoCState, busdev));
>> +
>> + /* 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 = salve4 & 0x000fffff, size = 6KB */
>
> A typo: salve
>
Got it, thanks
>> + s->rom_base = s->ahb_slave[4] & 0xfff00000;
>> + s->rom_size = 6 << 10;
>> +
>> + /* RAM base = salve6 & 0x000fffff, size <= (1 << slave6.BIT[19-16]) MB
>> */
>
> and here too
>
>> + 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 */
>> + if (!s->cpu_model) {
>> + s->cpu_model = (char *)"fa626te";
>> + }
>> + s->cpu = cpu_arm_init(s->cpu_model);
>> + if (!s->cpu) {
>> + hw_error("a369: Unable to find CPU definition\n");
>> + exit(1);
>> + }
>> +
>> + /* RAM Init */
>> + memory_region_init_ram(s->ram, "a369.ram", s->ram_size);
>> + vmstate_register_ram_global(s->ram);
>> +
>> + /* Embedded RAM Init */
>> + memory_region_init_ram(s->sram, "a369.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,
>> + "a369.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) {
>> + hw_error("a369soc: failed to init ROM device.\n");
>> + exit(1);
>> + }
>> +
>> + /* Serial (FTUART010 which is 16550A compatible) */
>> + if (serial_hds[0]) {
>> + serial_mm_init(s->as,
>> + 0x92b00000,
>> + 2,
>> + NULL,
>> + 18432000,
>> + serial_hds[0],
>> + DEVICE_LITTLE_ENDIAN);
>> + }
>> + if (serial_hds[1]) {
>> + serial_mm_init(s->as,
>> + 0x92c00000,
>> + 2,
>> + NULL,
>> + 18432000,
>> + serial_hds[1],
>> + DEVICE_LITTLE_ENDIAN);
>> + }
>> +
>> + /* ftscu010 */
>> + ds = sysbus_create_simple("a369.scu", 0x92000000, NULL);
>> + s->scu = ds;
>> +
>> + /* ftkbc010 */
>> + sysbus_create_simple("a369.keypad", 0x92f00000, NULL);
>> +}
>> +
>> +static int a369soc_init(SysBusDevice *busdev)
>> +{
>> + FaradaySoCState *s = FARADAY_SOC(FROM_SYSBUS(FaradaySoCState, busdev));
>> +
>> + a369soc_reset(DEVICE(busdev));
>> + a369soc_device_init(s);
>> +
>> + return 0;
>> +}
>> +
>> +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)
>> +{
>> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + k->init = a369soc_init;
>> + dc->desc = TYPE_FARADAY_SOC;
>> + dc->vmsd = &vmstate_a369soc;
>> + dc->props = a369soc_properties;
>> + dc->reset = a369soc_reset;
>> + 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..48e39e1
>> --- /dev/null
>> +++ b/hw/arm/ftkbc010.h
>> @@ -0,0 +1,42 @@
>> +/*
>> + * 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
>> +
>> +#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 */
>
> I think its a good idea to include a header where BIT() macro is defined.
>
>
Got it, thanks
>> +
>> +#endif
--
Best wishes,
Kuo-Jung Su