diff mbox

[01/18] hw: add Faraday a369 SoC platform support

Message ID 1358490506-18281-1-git-send-email-dantesu@faraday-tech.com
State New
Headers show

Commit Message

Dante Jan. 18, 2013, 6:28 a.m. UTC
Faraday A369, is an ARM SoC prototype chip, highly integrated with common SoC
features, including a 533MHz ARM v5TE master CPU, a 133MHz ARM v5TE slave CPU,
a 32-bit DDR-2 533MHz memory controller, 2 USB 2.0 host/OTG ports, SATA
host/device port, 10/100/1000 Ethernet port, MPEG4 codec, H.264 decoder,
image signal processor, and various low-speed peripheral interfaces.

This patch adds QEMU model for A369 without MPEG4/H.264 and USB support.
The USB host is still under migration from qemu-1.3.0 into the current
development release from GIT.

These patches include:

1. hw/a369.c:        QEMU model for Faraday a369 SoC platform
2. hw/a369_scu.c:    A369 System Control Uint (Clock & Power Management)
3. hw/ftapbbrg020.c: APB DMA Engine
4. hw/ftapbbrg020.h
5. hw/ftdmac020.c:   AHB DMA Engine
6. hw/ftdmac020.h
7. hw/ftgmac100.c:   1Gbps Ethernet MAC
8. hw/ftgmac100.h
9. hw/fti2c010.c:    I2C Master
10.hw/fti2c010.h
11.hw/ftintc020.c:   Interrupt Controller
12.hw/ftkbc010.c:    A369 Keypad Controller
13.hw/ftlcdc200.c:   LCD Controller
14.hw/ftlcdc200.h
15.hw/ftlcdc200_template.h
16.hw/ftmac110.c:    100Mbps Ethernet MAC
17.hw/ftmac110.h
18.hw/ftnandc021.c:  NAND Flash Controller
19.hw/ftnandc021.h
20.hw/ftpwmtmr010.c: Timer
21.hw/ftrtc011.c:    RTC Timer
22.hw/ftsdc010.c:    MMC/SD Host Controller
23.hw/ftsdc010.h
24.hw/ftspi020.c:    SPI NOR Flash Controller
25.hw/ftspi020.h
26.hw/ftssp010.c:    Multi-function device with SPI and I2S support
27.hw/ftssp010.h
28.hw/fttmr010.c:    Timer
29/hw/fttsc010.c:    Touchscreen Controller
30.hw/fttsc010.h
31.hw/ftwdt010.c:    Watchdog Timer
32.hw/rom.c:         Embedded ROM device model for SoC Platform

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/a369.c            |  499 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/a369_scu.c        |  192 +++++++++++++++++++
 hw/arm/Makefile.objs |    6 +
 3 files changed, 697 insertions(+)
 create mode 100644 hw/a369.c
 create mode 100644 hw/a369_scu.c

Comments

Blue Swirl Jan. 19, 2013, 8:15 a.m. UTC | #1
On Fri, Jan 18, 2013 at 6:28 AM, Dante <dantesu@faraday-tech.com> wrote:
> Faraday A369, is an ARM SoC prototype chip, highly integrated with common SoC
> features, including a 533MHz ARM v5TE master CPU, a 133MHz ARM v5TE slave CPU,
> a 32-bit DDR-2 533MHz memory controller, 2 USB 2.0 host/OTG ports, SATA
> host/device port, 10/100/1000 Ethernet port, MPEG4 codec, H.264 decoder,
> image signal processor, and various low-speed peripheral interfaces.
>
> This patch adds QEMU model for A369 without MPEG4/H.264 and USB support.
> The USB host is still under migration from qemu-1.3.0 into the current
> development release from GIT.
>
> These patches include:

The cover letter in git send-email will generate this for you, please
use that instead.

>
> 1. hw/a369.c:        QEMU model for Faraday a369 SoC platform
> 2. hw/a369_scu.c:    A369 System Control Uint (Clock & Power Management)
> 3. hw/ftapbbrg020.c: APB DMA Engine
> 4. hw/ftapbbrg020.h
> 5. hw/ftdmac020.c:   AHB DMA Engine
> 6. hw/ftdmac020.h
> 7. hw/ftgmac100.c:   1Gbps Ethernet MAC
> 8. hw/ftgmac100.h
> 9. hw/fti2c010.c:    I2C Master
> 10.hw/fti2c010.h
> 11.hw/ftintc020.c:   Interrupt Controller
> 12.hw/ftkbc010.c:    A369 Keypad Controller
> 13.hw/ftlcdc200.c:   LCD Controller
> 14.hw/ftlcdc200.h
> 15.hw/ftlcdc200_template.h
> 16.hw/ftmac110.c:    100Mbps Ethernet MAC
> 17.hw/ftmac110.h
> 18.hw/ftnandc021.c:  NAND Flash Controller
> 19.hw/ftnandc021.h
> 20.hw/ftpwmtmr010.c: Timer
> 21.hw/ftrtc011.c:    RTC Timer
> 22.hw/ftsdc010.c:    MMC/SD Host Controller
> 23.hw/ftsdc010.h
> 24.hw/ftspi020.c:    SPI NOR Flash Controller
> 25.hw/ftspi020.h
> 26.hw/ftssp010.c:    Multi-function device with SPI and I2S support
> 27.hw/ftssp010.h
> 28.hw/fttmr010.c:    Timer
> 29/hw/fttsc010.c:    Touchscreen Controller
> 30.hw/fttsc010.h
> 31.hw/ftwdt010.c:    Watchdog Timer
> 32.hw/rom.c:         Embedded ROM device model for SoC Platform
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> ---
>  hw/a369.c            |  499 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/a369_scu.c        |  192 +++++++++++++++++++
>  hw/arm/Makefile.objs |    6 +
>  3 files changed, 697 insertions(+)
>  create mode 100644 hw/a369.c
>  create mode 100644 hw/a369_scu.c
>
> diff --git a/hw/a369.c b/hw/a369.c
> new file mode 100644
> index 0000000..cc78351
> --- /dev/null
> +++ b/hw/a369.c
> @@ -0,0 +1,499 @@
> +/*
> + * Faraday A369 Evalution Board
> + *
> + * Copyright (c) 2012 Faraday Technology
> + *
> + * Written by Dante Su <dantesu@faraday-tech.com>
> + *
> + * This code is licensed under the GPL.

Which version? We prefer "GPL v2 or later, at your option".

> + */
> +
> +#include "sysbus.h"
> +#include "arm-misc.h"
> +#include "devices.h"
> +#include "net/net.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/blockdev.h"
> +#include "exec/address-spaces.h"
> +#include "i2c.h"
> +#include "boards.h"
> +#include "flash.h"
> +#include "serial.h"
> +#include "ssi.h"
> +
> +#define A369_NOR_FLASH_ADDR            0x20000000
> +#define A369_NOR_FLASH_SIZE            (16 * 1024 * 1024)
> +#define A369_NOR_FLASH_SECT_SIZE    (128 * 1024)
> +
> +#ifndef min
> +#define min(a, b)                    ((a) < (b) ? (a) : (b))

Macro names should be uppercase.

> +#endif
> +
> +#ifndef max
> +#define max(a, b)                    ((a) > (b) ? (a) : (b))
> +#endif
> +
> +struct a369_ahbc_state {

Struct names should use CamelCase and don't forget the typedef as
instructed in HACKING.

> +    SysBusDevice busdev;
> +    MemoryRegion iomem;
> +    /* HW register cache */
> +    uint32_t cr;
> +};
> +
> +struct a369_ddrc_state {
> +    SysBusDevice busdev;
> +    MemoryRegion iomem;
> +
> +    /* HW register caches */
> +    uint32_t mcr;
> +    uint32_t msr;
> +};
> +
> +struct a369_state {
> +    ARMCPU *cpu;
> +    DeviceState *rom;
> +    DeviceState *hdma;    /* AHB DMA */
> +    DeviceState *pdma;    /* APB DMA */
> +
> +    MemoryRegion *as;
> +    MemoryRegion *ram;
> +    MemoryRegion *ram_alias;
> +    MemoryRegion *sram;
> +
> +    i2c_bus *i2c[2];
> +
> +    struct a369_ahbc_state ahbc;
> +    struct a369_ddrc_state ddrc;
> +};
> +
> +/* ftintc020.c */
> +qemu_irq *ftintc020_init(hwaddr base, ARMCPU *cpu);

Function prototypes belong to a header file.

> +
> +/* ftgmac100.c */
> +void ftgmac100_init(NICInfo *nd, uint32_t base, qemu_irq irq);
> +
> +/* AHB controller block */
> +
> +static uint64_t a369_ahbc_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    struct a369_state *mach = opaque;
> +    struct a369_ahbc_state *s = &mach->ahbc;
> +
> +    switch(addr) {
> +    case 0x00: return 0x94050000;
> +    case 0x04: return 0x96040000;
> +    case 0x08: return 0x90f00000;
> +    case 0x0c: return 0x92050000;
> +    case 0x10: return 0x20080000;
> +    case 0x14: return 0xc0080000;
> +    case 0x18: return 0x00090000;
> +    case 0x1c: return 0x90000000;
> +    case 0x20: return 0x90100000;
> +    case 0x24: return 0x90200000;
> +    case 0x28: return 0x90300000;
> +    case 0x2c: return 0x90400000;
> +    case 0x30: return 0x90500000;
> +    case 0x34: return 0x90600000;
> +    case 0x38: return 0x90700000;
> +    case 0x3c: return 0x90800000;
> +    case 0x40: return 0x90900000;
> +    case 0x44: return 0x90a00000;
> +    case 0x48: return 0x90b00000;
> +    case 0x4c: return 0x90c00000;
> +    case 0x50: return 0x90d00000;
> +    case 0x54: return 0x90e00000;
> +    case 0x58: return 0x40080000;
> +    case 0x5c: return 0x60080000;
> +    case 0x60: return 0xa0000000;
> +    case 0x84: return 0x00000001;
> +    case 0x88: return s->cr;
> +    case 0x8c: return 0x00010301;
> +    default:
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static void a369_ahbc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    struct a369_state *mach = opaque;
> +    struct a369_ahbc_state *s = &mach->ahbc;
> +
> +    if (addr == 0x88) {

Please use switch().

> +        if (!(s->cr & 0x01) && (val & 0x01)) {
> +            /* AHB remap */
> +            printf("[qemu] a369: AHB remap...\n");

Remove printfs or convert them to tracepoints or debug printfs.

> +            sysbus_mmio_map(sysbus_from_qdev(mach->rom), 0, 0x40000000);

Doesn't the previous mapping still stay?

> +            memory_region_del_subregion(mach->as, mach->ram_alias);
> +            memory_region_add_subregion(mach->as, 0x00000000, mach->ram);
> +        }
> +        s->cr = (uint32_t)val;
> +    }
> +}
> +
> +static const MemoryRegionOps a369_ahbc_ops = {
> +    .read  = a369_ahbc_read,
> +    .write = a369_ahbc_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static int a369_ahbc_init(struct a369_state *mach, hwaddr base)
> +{
> +    struct a369_ahbc_state *s = &mach->ahbc;
> +    memory_region_init_io(&s->iomem, &a369_ahbc_ops, mach, "a369_ahbc", 0x1000);
> +    memory_region_add_subregion(mach->as, base, &s->iomem);
> +    s->cr = 0;
> +    return 0;
> +}
> +
> +/* DDRII controller block */
> +
> +static uint64_t a369_ddrc_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    struct a369_state *mach = opaque;
> +    struct a369_ddrc_state *s = &mach->ddrc;
> +
> +    switch(addr) {
> +    case 0x00:
> +        return s->mcr;
> +    case 0x04:
> +        return s->msr;
> +    default:
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static void a369_ddrc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    struct a369_state *mach = opaque;
> +    struct a369_ddrc_state *s = &mach->ddrc;
> +
> +    switch(addr) {
> +    case 0x00:
> +        s->mcr = (uint32_t)val & 0xffff;
> +        break;
> +    case 0x04:
> +        val = (val & 0x3f) | (s->msr & 0x100);
> +        if (!(s->msr & 0x100) && (val & 0x01)) {
> +            val &= 0xfffffffe;
> +            val |= 0x100;
> +            printf("[qemu] a369: ddr init...\n");
> +            memory_region_add_subregion(mach->as, 0x10000000, mach->ram_alias);
> +        }
> +        s->msr = (uint32_t)val;
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps a369_ddrc_ops = {
> +    .read  = a369_ddrc_read,
> +    .write = a369_ddrc_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static int a369_ddrc_init(struct a369_state *mach, hwaddr base)
> +{
> +    struct a369_ddrc_state *s = &mach->ddrc;
> +
> +    memory_region_init_io(&s->iomem, &a369_ddrc_ops, mach, "a369_ddrc", 0x1000);
> +    memory_region_add_subregion(mach->as, base, &s->iomem);
> +    s->mcr = 0;
> +    s->msr = 0;
> +    return 0;
> +}
> +
> +/* Board init.  */
> +
> +static void a369_device_init(struct a369_state *s)
> +{
> +    qemu_irq *pic;
> +    DeviceState *ds;
> +    int done_nic = 0;
> +    int i;
> +
> +    /* Interrupt Controller */
> +    pic = ftintc020_init(0x90100000, s->cpu);
> +
> +    /* Timer */
> +    ds = qdev_create(NULL, "ftpwmtmr010");
> +    qdev_prop_set_uint32(ds, "freq", 66 * 1000000);
> +    qdev_init_nofail(ds);
> +    sysbus_mmio_map(sysbus_from_qdev(ds), 0, 0x92300000);
> +    sysbus_connect_irq(sysbus_from_qdev(ds), 0, pic[8]);
> +    sysbus_connect_irq(sysbus_from_qdev(ds), 1, pic[9]);
> +    sysbus_connect_irq(sysbus_from_qdev(ds), 2, pic[10]);
> +    sysbus_connect_irq(sysbus_from_qdev(ds), 3, pic[11]);
> +
> +    /* Serial (FTUART010 which is 16550A compatible) */
> +    if (serial_hds[0]) {
> +        serial_mm_init(s->as,
> +                       0x92b00000,
> +                       2,
> +                       pic[53],
> +                       18432000 / 16,
> +                       serial_hds[0],
> +                       DEVICE_NATIVE_ENDIAN);

DEVICE_NATIVE_ENDIAN would indicate that the device is very close to
CPU. Probably DEVICE_LITTLE_ENDIAN would make more sense.

> +    }
> +    if (serial_hds[1]) {
> +        serial_mm_init(s->as,
> +                       0x92c00000,
> +                       2,
> +                       pic[54],
> +                       18432000 / 16,
> +                       serial_hds[1],
> +                       DEVICE_NATIVE_ENDIAN);
> +    }
> +
> +    /* ftscu010 */
> +    sysbus_create_simple("a369_scu", 0x92000000, pic[41]);
> +
> +    /* ftdmac020 */
> +    s->hdma = sysbus_create_simple("ftdmac020", 0x90300000, pic[15]);
> +    sysbus_create_simple("ftdmac020", 0x96100000, pic[17]);
> +
> +    /* ftapbbrg020 */
> +    s->pdma = sysbus_create_simple("ftapbbrg020", 0x90f00000, pic[14]);
> +
> +    /* ftnandc021 */
> +    do {

Just move the variable definitions to the start of the function, or
extract to a separate function.

> +        qemu_irq ack, req;
> +        ds = sysbus_create_simple("ftnandc021", 0x90200000, pic[30]);
> +        ack = qdev_get_gpio_in(ds, 0);
> +        req = qdev_get_gpio_in(s->hdma, 15);
> +        qdev_connect_gpio_out(s->hdma, 15, ack);
> +        qdev_connect_gpio_out(ds, 0, req);
> +    } while(0);
> +
> +    /* ftsdc010 */
> +#if 0

No disabled or commented out code, please. They will just bit rot.

> +    do {
> +        qemu_irq ack, req;
> +        ds = sysbus_create_simple("ftsdc010", 0x90500000, pic[38]);
> +        ack = qdev_get_gpio_in(ds, 0);
> +        req = qdev_get_gpio_in(s->hdma, 14);
> +        qdev_connect_gpio_out(s->hdma, 14, ack);
> +        qdev_connect_gpio_out(ds, 0, req);
> +    } while(0);
> +#endif
> +    do {
> +        qemu_irq ack, req;
> +        ds = sysbus_create_simple("ftsdc010", 0x90600000, pic[39]);
> +        ack = qdev_get_gpio_in(ds, 0);
> +        req = qdev_get_gpio_in(s->hdma, 13);
> +        qdev_connect_gpio_out(s->hdma, 13, ack);
> +        qdev_connect_gpio_out(ds, 0, req);
> +    } while(0);
> +
> +#if 0
> +    /* fusbh200 */
> +    sysbus_create_simple("faraday-ehci-usb", 0x90800000, pic[36]);
> +
> +    /* fotg210 */
> +    sysbus_create_simple("faraday-ehci-usb", 0x90900000, pic[37]);
> +#endif
> +
> +    /* ftgmac100 */
> +    for(i = 0; i < nb_nics; i++) {

Space between 'for' and '('.

> +        NICInfo *nd = &nd_table[i];
> +        if (!done_nic && (!nd->model || strcmp(nd->model, "ftgmac100") == 0)) {
> +            ftgmac100_init(nd, 0x90c00000, pic[32]);
> +            done_nic = 1;
> +        }
> +    }
> +
> +    /* ftrtc011 (only alarm interrupt is connected) */
> +    sysbus_create_varargs("ftrtc011", 0x92100000, pic[0],    /* Alarm (Level): NC in A369 */
> +                                                  pic[42],    /* Alarm (Edge) */
> +                                                  pic[43],    /* Second (Edge) */
> +                                                  pic[44],    /* Minute (Edge) */
> +                                                  pic[45],    /* Hour (Edge) */
> +                                                  NULL);
> +
> +    /* ftwdt010 */
> +    sysbus_create_simple("ftwdt010", 0x92200000, pic[46]);
> +
> +    /* fttsc010 */
> +    sysbus_create_simple("fttsc010", 0x92400000, pic[19]);
> +
> +    /* ftkbc010 */
> +    sysbus_create_simple("ftkbc010", 0x92f00000, pic[21]);
> +
> +    /* ftlcdc200 */
> +    sysbus_create_varargs("ftlcdc200",0x94a00000, pic[0],  /* Global (NC in A369) */
> +                                                  pic[25], /* VSTATUS */
> +                                                  pic[24], /* Base Address Update */
> +                                                  pic[23], /* FIFO Under-Run */
> +                                                  pic[22], /* AHB Bus Error */
> +                                                  NULL);
> +
> +    /* fti2c010 */
> +    ds = sysbus_create_simple("fti2c010", 0x92900000, pic[51]);
> +    s->i2c[0] = (i2c_bus *)qdev_get_child_bus(ds, "i2c");
> +    ds = sysbus_create_simple("fti2c010", 0x92A00000, pic[52]);
> +    s->i2c[1] = (i2c_bus *)qdev_get_child_bus(ds, "i2c");
> +
> +    /* ftssp010 */
> +    do {
> +        SSIBus *spi;
> +        DeviceState *fl;
> +        int nr_flash = 1;
> +        qemu_irq cs_line;
> +        qemu_irq ack, req;
> +
> +        ds = qdev_create(NULL, "ftssp010");
> +
> +        /* i2s */
> +        qdev_prop_set_ptr(ds, "codec_i2c", s->i2c[0]);
> +        qdev_init_nofail(ds);
> +        sysbus_mmio_map(sysbus_from_qdev(ds), 0, 0x92700000);
> +        sysbus_connect_irq(sysbus_from_qdev(ds), 0, pic[49]);
> +
> +        /* spi */
> +        spi = (SSIBus *)qdev_get_child_bus(ds, "spi");
> +        for (i = 0; i < nr_flash; i++) {
> +            fl = ssi_create_slave_no_init(spi, "m25p80");
> +            qdev_prop_set_string(fl, "partname", "w25q64");
> +            qdev_init_nofail(fl);
> +            cs_line = qdev_get_gpio_in(fl, 0);
> +            sysbus_connect_irq(sysbus_from_qdev(ds), i+1, cs_line);
> +        }
> +
> +        /* DMA (Tx) */
> +        ack = qdev_get_gpio_in(ds, 0);
> +        req = qdev_get_gpio_in(s->pdma, 7);
> +        qdev_connect_gpio_out(s->pdma, 7, ack);
> +        qdev_connect_gpio_out(ds, 0, req);
> +
> +        /* DMA (Rx) */
> +        ack = qdev_get_gpio_in(ds, 1);
> +        req = qdev_get_gpio_in(s->pdma, 8);
> +        qdev_connect_gpio_out(s->pdma, 8, ack);
> +        qdev_connect_gpio_out(ds, 1, req);
> +    } while(0);
> +
> +    /* ftddrII030 */
> +    a369_ddrc_init(s, 0x93100000);
> +
> +    /* ftahbc020 */
> +    a369_ahbc_init(s, 0x94000000);
> +
> +    /* Parallel NOR Flash */
> +    do {
> +        DriveInfo *dinfo = drive_get_next(IF_PFLASH);
> +        if (!pflash_cfi01_register(
> +                        A369_NOR_FLASH_ADDR,
> +                        NULL,
> +                        "a369.pflash",
> +                        A369_NOR_FLASH_SIZE,
> +                        dinfo ? dinfo->bdrv : NULL,
> +                        A369_NOR_FLASH_SECT_SIZE,
> +                        A369_NOR_FLASH_SIZE / A369_NOR_FLASH_SECT_SIZE,
> +                        2, 0x0001, 0x227E, 0x2101, 0x0, 0)) {
> +            fprintf(stderr, "qemu: Error registering flash memory.\n");

exit(), hw_error()?

> +        }
> +    } while(0);
> +}
> +
> +static void a369_board_reset(void *opaque)
> +{
> +    struct a369_state *s = opaque;
> +
> +    if (s->ddrc.msr) {
> +        s->ddrc.mcr = 0;
> +        s->ddrc.msr = 0;
> +        if (s->ahbc.cr) {
> +            /* AHB remapped */
> +            sysbus_mmio_map(sysbus_from_qdev(s->rom), 0, 0x00000000);
> +            memory_region_del_subregion(s->as, s->ram);
> +        } else {
> +            /* AHB is not yet remapped, but SDRAM is ready */
> +            memory_region_del_subregion(s->as, s->ram_alias);
> +        }
> +        s->ahbc.cr = 0;
> +    }
> +
> +    cpu_reset(CPU(s->cpu));
> +}
> +
> +static void a369_board_init(QEMUMachineInitArgs *args)
> +{
> +    struct a369_state *s = g_new(struct a369_state, 1);
> +
> +    s->as = get_system_memory();
> +    s->ram  = g_new(MemoryRegion, 1);
> +    s->sram = g_new(MemoryRegion, 1);
> +
> +    /* CPU */
> +    if (!args->cpu_model)

Please use checkpatch.pl to catch brace problems.

> +        args->cpu_model = "fa626te";
> +
> +    s->cpu = cpu_arm_init(args->cpu_model);
> +    if (!s->cpu) {
> +        fprintf(stderr, "Unable to find CPU definition\n");
> +        exit(1);
> +    }
> +
> +    /* A369 supports upto 1GB ram space */
> +    if (args->ram_size > 0x40000000)
> +        args->ram_size = 0x40000000;
> +
> +    printf("qemu: faraday a369 with %dMB ram.\n", args->ram_size >> 20);
> +
> +    /* Embedded ROM Init */
> +    s->rom = qdev_create(NULL, "rom");
> +    qdev_prop_set_uint32(s->rom, "size", 8192);
> +    qdev_init_nofail(s->rom);
> +
> +    /* 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);
> +
> +    /* RAM Init */
> +    memory_region_init_ram(s->ram, "a369.ram", args->ram_size);
> +    vmstate_register_ram_global(s->ram);
> +
> +    a369_device_init(s);
> +    qemu_register_reset(a369_board_reset, s);
> +
> +    if (args->kernel_filename) {
> +        struct arm_boot_info *bi = g_new(struct arm_boot_info, 1);
> +
> +        /* RAM Address Binding */
> +        memory_region_add_subregion(s->as, 0x00000000, s->ram);
> +
> +        /* Boot Info */
> +        memset(bi, 0, sizeof(*bi));
> +        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 = 0xa369;
> +        arm_load_kernel(s->cpu, bi);
> +    } else {
> +        /* ROM Address Binding */
> +        sysbus_mmio_map(sysbus_from_qdev(s->rom), 0, 0x00000000);
> +        /* Partial RAM (before ahb remapped) Address Binding */
> +        s->ram_alias = g_new(MemoryRegion, 1);
> +        memory_region_init_alias(s->ram_alias, "a369.ram_alias",
> +                                 s->ram,
> +                                 0,
> +                                 min(0x10000000, args->ram_size));
> +    }
> +}
> +
> +static QEMUMachine a369_machine = {
> +    .name = "a369",
> +    .desc = "Faraday A369 (fa626te)",
> +    .init = a369_board_init,
> +};
> +
> +static void a369_machine_init(void)
> +{
> +    qemu_register_machine(&a369_machine);
> +}
> +
> +machine_init(a369_machine_init);
> diff --git a/hw/a369_scu.c b/hw/a369_scu.c
> new file mode 100644
> index 0000000..ee548d4
> --- /dev/null
> +++ b/hw/a369_scu.c
> @@ -0,0 +1,192 @@
> +/*
> + * QEMU model of the A369 SCU
> + *
> + * Copyright (C) 2012 Faraday Technology
> + * Copyright (C) 2012 Dante Su <dantesu@faraday-tech.com>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "sysbus.h"
> +#include "sysemu/sysemu.h"
> +
> +typedef struct {

The struct should also have a name.

> +    SysBusDevice busdev;
> +    MemoryRegion iomem;
> +    qemu_irq     irq;
> +
> +    /* HW register caches */
> +    uint32_t general_cfg;
> +    uint32_t sclk_cfg0;
> +    uint32_t sclk_cfg1;
> +    uint32_t mfpsr0;
> +    uint32_t mfpsr1;
> +
> +} a369_scu_state;
> +
> +static uint64_t
> +a369_scu_mem_read(void *opaque, hwaddr addr, unsigned int size)
> +{
> +    a369_scu_state *s = opaque;
> +
> +    switch(addr) {
> +    case 0x000:
> +        return 0x00003369;
> +    case 0x004:
> +        return 0x00010000;
> +    case 0x008:
> +        return 0x00000c10;
> +    case 0x00c:
> +        return 0x00000230;
> +    case 0x010:
> +        return 0x00000083;
> +    case 0x014:
> +        return 0x00000100;
> +    case 0x01C:
> +        return 0x00000003;
> +    case 0x020:
> +        return 0x20010003;
> +    case 0x024:
> +        return 0x00000003;
> +    case 0x060:
> +        return 0x00280028;
> +    case 0x200:
> +        return s->general_cfg;
> +    case 0x204:
> +        return 0x00001cc8;
> +    case 0x228:
> +        return s->sclk_cfg0;
> +    case 0x22c:
> +        return s->sclk_cfg1;
> +    case 0x230:
> +        return 0x00003fff;
> +    case 0x238:
> +        return s->mfpsr0;
> +    case 0x23c:
> +        return s->mfpsr1;
> +    case 0x240:
> +        return 0x11111111;
> +    case 0x244:
> +        return 0x11111111;
> +    case 0x254:
> +        return 0x00000303;
> +    case 0x258:
> +        return 0x8000007f;
> +    }
> +
> +    return 0;
> +}
> +
> +static void
> +a369_scu_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size)
> +{
> +    a369_scu_state *s = opaque;
> +
> +    switch(addr) {
> +    case 0x200:
> +        s->general_cfg = (uint32_t)val;
> +        break;
> +    case 0x228:
> +        s->sclk_cfg0 = (uint32_t)val;
> +        break;
> +    case 0x22c:
> +        s->sclk_cfg1 = (uint32_t)val;
> +        break;
> +    case 0x238:
> +        s->mfpsr0 = (uint32_t)val;
> +        break;
> +    case 0x23c:
> +        s->mfpsr1 = (uint32_t)val;
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps bus_ops = {
> +    .read  = a369_scu_mem_read,
> +    .write = a369_scu_mem_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4
> +    }
> +};
> +
> +static void a369_scu_reset(DeviceState *d)
> +{
> +    a369_scu_state *s = DO_UPCAST(a369_scu_state, busdev.qdev, d);
> +
> +    s->general_cfg = 0x00001078;
> +    s->sclk_cfg0   = 0x26877330;
> +    s->sclk_cfg1   = 0x000a0a0a;
> +    s->mfpsr0      = 0x00000241;
> +    s->mfpsr1      = 0x00000000;
> +}
> +
> +static int a369_scu_init(SysBusDevice *dev)
> +{
> +    a369_scu_state *s = FROM_SYSBUS(typeof(*s), dev);
> +
> +    memory_region_init_io(&s->iomem, &bus_ops, s, "a369_scu", 0x1000);
> +    sysbus_init_mmio(dev, &s->iomem);
> +    sysbus_init_irq(dev, &s->irq);
> +
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_a369_scu = {
> +    .name = "a369_scu",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(general_cfg, a369_scu_state),
> +        VMSTATE_UINT32(sclk_cfg0, a369_scu_state),
> +        VMSTATE_UINT32(sclk_cfg1, a369_scu_state),
> +        VMSTATE_UINT32(mfpsr0, a369_scu_state),
> +        VMSTATE_UINT32(mfpsr1, a369_scu_state),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void a369_scu_class_init(ObjectClass *klass, void *data)
> +{
> +    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
> +    DeviceClass *k = DEVICE_CLASS(klass);
> +
> +    sdc->init  = a369_scu_init;
> +    k->vmsd    = &vmstate_a369_scu;
> +    k->reset   = a369_scu_reset;
> +    k->no_user = 1;
> +}
> +
> +static TypeInfo a369_scu_info = {
> +    .name           = "a369_scu",
> +    .parent         = TYPE_SYS_BUS_DEVICE,
> +    .instance_size  = sizeof(a369_scu_state),
> +    .class_init     = a369_scu_class_init,
> +};
> +
> +static void a369_scu_register_types(void)
> +{
> +    type_register_static(&a369_scu_info);
> +}
> +
> +type_init(a369_scu_register_types)
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 6d049e7..4cc85e5 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -1,4 +1,10 @@
>  obj-y = integratorcp.o versatilepb.o arm_pic.o
> +obj-y += a369.o a369_scu.o \
> +                               rom.o ftdmac020.o ftapbbrg020.o \
> +                               ftintc020.o fttmr010.o ftpwmtmr010.o \
> +                               ftspi020.o ftssp010.o fti2c010.o \
> +                               ftrtc011.o ftwdt010.o ftmac110.o ftgmac100.o ftlcdc200.o \
> +                               fttsc010.o ftkbc010.o ftnandc021.o ftsdc010.o
>  obj-y += arm_boot.o
>  obj-y += xilinx_zynq.o zynq_slcr.o
>  obj-y += xilinx_spips.o
> --
> 1.7.9.5
>
>
> ********************* Confidentiality Notice ************************
> This electronic message and any attachments may contain
> confidential and legally privileged information or
> information which is otherwise protected from disclosure.
> If you are not the intended recipient,please do not disclose
> the contents, either in whole or in part, to anyone,and
> immediately delete the message and any attachments from
> your computer system and destroy all hard copies.
> Thank you for your cooperation.
> ***********************************************************************
>
>
Kuo-Jung Su Jan. 25, 2013, 8:19 a.m. UTC | #2
From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Faraday provides ARMv4/ARMv5TE compatible solutions, 
and focus on ASIC design service. 

Here are some public documents for you reference.

http://www.faraday-tech.com/html/documentation/index.html

The pre-built images are also available at my Google Drive:

https://docs.google.com/folder/d/0BwfiewvSmUgAX2pTTmtUMGFCZW8/edit

Here is the image file list:

1. android-4.0.4/zImage: A369 linux-3.0.31
2. android-4.0.4/romfs-4.0.4.tar.bz2: android-4.0.4
3. nand.img.bz2: A369 nand flash image
4. rom.img.bz2: A369 embedded ROM image
5. u-boot: A369 u-boot-2012.10 ELF file
6. zImage: A369 linux-3.4.12 + initramfs
7. README

Changes for v2:

   1. coding style fixes (verified with checkpatch.pl)
   2. add Faraday A360 support
   3. add Faraday USB 2.0 EHCI support
   4. merge a369_scu.c into a369.c
   5. introduce QOM coding style
   6. remove lowercase Macros: min(), max()
   7. name all struct as CamelCase style
   8. move function prototypes from .c to faraday.h
   9. use switch instead of if statement in a369_ahbc_write
  10. remove debug prints
  11. update all uarts in A36x to DEVICE_LITTLE_ENDIAN.
  12. move the variable definitions to the start of the function,
      instead of inside a do { } while(0)
  13. remove disabled and commented out code.
  14. use hw_error() and exit() upon pflash register failed.
  15. add const prior to TypeInfo (i.e. static *const* 
      TypeInfo ftrtc011_info)
  16. add le32_to_cpu/cpu_to_le32 to the descriptor processing in 
      FTGMAC100/FTMAC110.
  17. update the GPL license to GPL v2 (except for FTLCDC200, 
      it's based on pl110.c which is LGPL.)
  18. add const to src_* in the DMA controllers (FTAPBBRG020/FTDMAC020)

  Note:   
  1. Thanks to the comments from KONRAD, Andreas, Paul and Blue.
     But if there is still something missed, please kindly remind me to fix.
     Thanks!
  
  2. There are still two coding style errors reported by checkpatch.pl,
     but I think they might be false alarms, here is the error log:

  ERROR: need consistent spacing around '*' (ctx:WxV)
  #74: FILE: hw/a360.c:32:
  +    i2c_bus      *i2c[2];                ^

  ERROR: open brace '{' following function declarations go on the next line
  #4680: FILE: hw/ftlcdc200_template.h:59:
  +static drawfn glue(ftlcdc200_draw_fn_, BITS)[48] = {


Kuo-Jung Su (20):
  arm: add Faraday a36x SoC platform support
  arm: add Faraday FUSBH200 EHCI controller support
  arm: add Faraday FTAPBBRG020 APB DMA support
  arm: add Faraday FTDMAC020 AHB DMA support
  arm: add Faraday FTGMAC100 1Gbps ethernet support
  arm: add Faraday FTMAC110 10/100Mbps ethernet support
  arm: add Faraday FTI2C010 I2C controller support
  arm: add Faraday FTLCDC200 LCD controller support
  arm: add Faraday FTNANDC021 nand flash controller support
  arm: add Faraday FTSDC010 MMC/SD controller support
  arm: add Faraday FTTSC010 touchscreen controller support
  arm: add Faraday FTSSP010 multi-function controller support
  arm: add Faraday FTSPI020 spi flash controller support
  arm: add Faraday FTRTC011 RTC timer support
  arm: add Faraday FTWDT010 watchdog timer support
  arm: add Faraday FTTMR010 timer support
  arm: add Faraday FTPWMTMR010 timer support
  arm: add Faraday FTINTC020 interrupt controller support
  arm: add Faraday FTKBC010 support for A369
  arm: add generic ROM model for Faraday SoC platforms

 .gitignore               |    1 +
 hw/a360.c                |  271 +++++++++++++++++++
 hw/a369.c                |  581 ++++++++++++++++++++++++++++++++++++++++
 hw/arm/Makefile.objs     |    6 +
 hw/faraday.h             |   21 ++
 hw/ftapbbrg020.c         |  502 ++++++++++++++++++++++++++++++++++
 hw/ftapbbrg020.h         |   41 +++
 hw/ftdmac020.c           |  667 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/ftdmac020.h           |  105 ++++++++
 hw/ftgmac100.c           |  647 ++++++++++++++++++++++++++++++++++++++++++++
 hw/ftgmac100.h           |  177 ++++++++++++
 hw/fti2c010.c            |  205 ++++++++++++++
 hw/fti2c010.h            |   62 +++++
 hw/ftintc020.c           |  354 ++++++++++++++++++++++++
 hw/ftkbc010.c            |  226 ++++++++++++++++
 hw/ftlcdc200.c           |  505 +++++++++++++++++++++++++++++++++++
 hw/ftlcdc200.h           |  110 ++++++++
 hw/ftlcdc200_template.h  |  439 ++++++++++++++++++++++++++++++
 hw/ftmac110.c            |  591 ++++++++++++++++++++++++++++++++++++++++
 hw/ftmac110.h            |  131 +++++++++
 hw/ftnandc021.c          |  514 +++++++++++++++++++++++++++++++++++
 hw/ftnandc021.h          |   55 ++++
 hw/ftpwmtmr010.c         |  244 +++++++++++++++++
 hw/ftrtc011.c            |  315 ++++++++++++++++++++++
 hw/ftsdc010.c            |  363 +++++++++++++++++++++++++
 hw/ftsdc010.h            |   88 ++++++
 hw/ftspi020.c            |  345 ++++++++++++++++++++++++
 hw/ftspi020.h            |   50 ++++
 hw/ftssp010.c            |  552 ++++++++++++++++++++++++++++++++++++++
 hw/ftssp010.h            |   91 +++++++
 hw/fttmr010.c            |  468 ++++++++++++++++++++++++++++++++
 hw/fttsc010.c            |  260 ++++++++++++++++++
 hw/fttsc010.h            |   23 ++
 hw/ftwdt010.c            |  213 +++++++++++++++
 hw/rom.c                 |  119 +++++++++
 hw/usb/hcd-ehci-sysbus.c |   23 ++
 hw/usb/hcd-ehci.c        |   51 +++-
 hw/usb/hcd-ehci.h        |   14 +-
 38 files changed, 9416 insertions(+), 14 deletions(-)
 create mode 100644 hw/a360.c
 create mode 100644 hw/a369.c
 create mode 100644 hw/faraday.h
 create mode 100644 hw/ftapbbrg020.c
 create mode 100644 hw/ftapbbrg020.h
 create mode 100644 hw/ftdmac020.c
 create mode 100644 hw/ftdmac020.h
 create mode 100644 hw/ftgmac100.c
 create mode 100644 hw/ftgmac100.h
 create mode 100644 hw/fti2c010.c
 create mode 100644 hw/fti2c010.h
 create mode 100644 hw/ftintc020.c
 create mode 100644 hw/ftkbc010.c
 create mode 100644 hw/ftlcdc200.c
 create mode 100644 hw/ftlcdc200.h
 create mode 100644 hw/ftlcdc200_template.h
 create mode 100644 hw/ftmac110.c
 create mode 100644 hw/ftmac110.h
 create mode 100644 hw/ftnandc021.c
 create mode 100644 hw/ftnandc021.h
 create mode 100644 hw/ftpwmtmr010.c
 create mode 100644 hw/ftrtc011.c
 create mode 100644 hw/ftsdc010.c
 create mode 100644 hw/ftsdc010.h
 create mode 100644 hw/ftspi020.c
 create mode 100644 hw/ftspi020.h
 create mode 100644 hw/ftssp010.c
 create mode 100644 hw/ftssp010.h
 create mode 100644 hw/fttmr010.c
 create mode 100644 hw/fttsc010.c
 create mode 100644 hw/fttsc010.h
 create mode 100644 hw/ftwdt010.c
 create mode 100644 hw/rom.c
Andreas Färber Jan. 25, 2013, 9:07 a.m. UTC | #3
Am 25.01.2013 09:19, schrieb Kuo-Jung Su:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> The Faraday A360/A369 EVB is a Faraday platform main board used for the
> Faraday IP functional verification based on the well-known ARM AMBA 2.0
> architecture. This main board provides a fully verified microprocessor
> platform, ATA-II, OTG 2.0 and USB 2.0 host connectivity.
> 
> Faraday A360 EVB provides the on-board DDR2-SODIMM (256 MB),
> NAND Flash (128 MB), USB2.0 interface, two PCI Express interfaces,
> two I2C interfaces, two SSP ports, Secure Digital interface, and a 12-bit
> A/D converter in addition to many other features.
> 
> Faraday A369 EVB provides the on-board DDR2-SODIMM (512 MB),
> NAND Flash (256 MB), SPI Flash ROM (16 MB), I2C EPROM, Giga-bit Ethernet,
> IDE, SATA host, OTG 2.0 and USB 2.0 host connectors, video output interface,
> TV encoder for video output, LCD controller interface, SD/MMC card reader
> interface, I2S codec, UART(X2), Multi-ICE, 80 ports, and an AHB extension bus.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> ---
>  hw/a360.c            |  271 +++++++++++++++++++++++
>  hw/a369.c            |  581 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/arm/Makefile.objs |    6 +
>  hw/faraday.h         |   21 ++
>  4 files changed, 879 insertions(+)
>  create mode 100644 hw/a360.c
>  create mode 100644 hw/a369.c
>  create mode 100644 hw/faraday.h
> 
> diff --git a/hw/a360.c b/hw/a360.c
> new file mode 100644
> index 0000000..cb0a588
> --- /dev/null
> +++ b/hw/a360.c
> @@ -0,0 +1,271 @@
> +/*
> + * Faraday A360 Evalution Board
> + *
> + * Copyright (c) 2012 Faraday Technology
> + * Written by Dante Su <dantesu@faraday-tech.com>
> + *
> + * This code is licensed under GNU GPL v2.

Can you please license this and any other files as "v2 or (at your
option) any later version"? Cf. http://wiki.qemu.org/Relicensing

Also, there is work underway to move target-specific files to the
subdirectories of hw/, i.e. suggest the new ARM machine should go to
hw/arm/faraday_a360.c as hw/ is terribly crowded today and a360 is
pretty generic. For devices it depends on whether they are tightly
coupled to the ARM SoC or reusable in any target (x86 etc.).

Regards,
Andreas
Andreas Färber Jan. 28, 2013, 7:22 a.m. UTC | #4
Am 25.01.2013 10:07, schrieb Andreas Färber:
> Am 25.01.2013 09:19, schrieb Kuo-Jung Su:
>>  hw/a360.c            |  271 +++++++++++++++++++++++
>>  hw/a369.c            |  581 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  hw/arm/Makefile.objs |    6 +
>>  hw/faraday.h         |   21 ++
>>  4 files changed, 879 insertions(+)
>>  create mode 100644 hw/a360.c
>>  create mode 100644 hw/a369.c
>>  create mode 100644 hw/faraday.h
>>
>> diff --git a/hw/a360.c b/hw/a360.c
>> new file mode 100644
>> index 0000000..cb0a588
>> --- /dev/null
>> +++ b/hw/a360.c
>> @@ -0,0 +1,271 @@
>> +/*
>> + * Faraday A360 Evalution Board
>> + *
>> + * Copyright (c) 2012 Faraday Technology
>> + * Written by Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This code is licensed under GNU GPL v2.
> 
> Can you please license this and any other files as "v2 or (at your
> option) any later version"? Cf. http://wiki.qemu.org/Relicensing
> 
> Also, there is work underway to move target-specific files to the
> subdirectories of hw/, i.e. suggest the new ARM machine should go to
> hw/arm/faraday_a360.c as hw/ is terribly crowded today and a360 is
> pretty generic.

The same applies to the machine names "a360" and "a369" - I feel they
are too ambiguous, given that there is an AllWinner A20 SoC for
instance. Can you consider renaming to something less ambiguous like
"faraday-a360" or so?

Andreas

> For devices it depends on whether they are tightly
> coupled to the ARM SoC or reusable in any target (x86 etc.).
> 
> Regards,
> Andreas
Andreas Färber Jan. 28, 2013, 7:41 a.m. UTC | #5
Am 25.01.2013 09:19, schrieb Kuo-Jung Su:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> These patches introduce Faraday A36x SoC platform support.
> 
> Faraday provides ARMv4/ARMv5TE compatible solutions, 
> and focus on ASIC design service. 
> 
> Here are some public documents for you reference.
> 
> http://www.faraday-tech.com/html/documentation/index.html
> 
> The pre-built images are also available at my Google Drive:
> 
> https://docs.google.com/folder/d/0BwfiewvSmUgAX2pTTmtUMGFCZW8/edit
> 
> Here is the image file list:
> 
> 1. android-4.0.4/zImage: A369 linux-3.0.31
> 2. android-4.0.4/romfs-4.0.4.tar.bz2: android-4.0.4
> 3. nand.img.bz2: A369 nand flash image
> 4. rom.img.bz2: A369 embedded ROM image
> 5. u-boot: A369 u-boot-2012.10 ELF file
> 6. zImage: A369 linux-3.4.12 + initramfs
> 7. README

Thank you for posting these test images. Could you also publish your
patches on some public git branch so that one doesn't need to manually
apply 20 or more patches to test it? (e.g., GitHub, repo.or.cz, ...)

Another thing you could look into is qemu-jeos.git support - could you
supply configs for building an upstream Linux kernel for testing? You
can look at arm-vexpress.cfg as template.

> Changes for v2:
> 
>    1. coding style fixes (verified with checkpatch.pl)
>    2. add Faraday A360 support
>    3. add Faraday USB 2.0 EHCI support
>    4. merge a369_scu.c into a369.c
>    5. introduce QOM coding style
>    6. remove lowercase Macros: min(), max()
>    7. name all struct as CamelCase style
>    8. move function prototypes from .c to faraday.h
>    9. use switch instead of if statement in a369_ahbc_write
>   10. remove debug prints
>   11. update all uarts in A36x to DEVICE_LITTLE_ENDIAN.
>   12. move the variable definitions to the start of the function,
>       instead of inside a do { } while(0)
>   13. remove disabled and commented out code.
>   14. use hw_error() and exit() upon pflash register failed.
>   15. add const prior to TypeInfo (i.e. static *const* 
>       TypeInfo ftrtc011_info)
>   16. add le32_to_cpu/cpu_to_le32 to the descriptor processing in 
>       FTGMAC100/FTMAC110.
>   17. update the GPL license to GPL v2 (except for FTLCDC200, 
>       it's based on pl110.c which is LGPL.)
>   18. add const to src_* in the DMA controllers (FTAPBBRG020/FTDMAC020)
> 
>   Note:   
>   1. Thanks to the comments from KONRAD, Andreas, Paul and Blue.
>      But if there is still something missed, please kindly remind me to fix.
>      Thanks!

Your detailed change log is very helpful, thank you. When you post a v3
however, please post the patch series as a top-level patchset (i.e., the
cover letter not as a reply, just the actual patches to the cover
letter), the change log then should be sufficient to understand its
historical context and that makes it a little easier for humans or
Anthony's scripts to find the latest patch versions.

For all your new SysBus devices (i.e., types with .parent =
SYS_BUS_DEVICE) please use a QOM realizefn instead of a qdev initfn -
not just the function naming but dc->realize rather than sdc->init. This
avoids one of us having to go through your code later and doing the
conversion. (I showed you how to do that for EHCI as an example.)

What I'm still missing in v2 is qtest test cases for the RTC and a
libqos driver for your I2C master. If you have questions how to go about
that, feel free to ask on IRC.

>   2. There are still two coding style errors reported by checkpatch.pl,
>      but I think they might be false alarms, here is the error log:
> 
>   ERROR: need consistent spacing around '*' (ctx:WxV)
>   #74: FILE: hw/a360.c:32:
>   +    i2c_bus      *i2c[2];                ^
> 
>   ERROR: open brace '{' following function declarations go on the next line
>   #4680: FILE: hw/ftlcdc200_template.h:59:
>   +static drawfn glue(ftlcdc200_draw_fn_, BITS)[48] = {

Yes, your analysis looks correct, you can ignore both "errors".

Regards,
Andreas
Kuo-Jung Su Jan. 28, 2013, 7:44 a.m. UTC | #6
sure, no problem.


2013/1/28 Andreas Färber <afaerber@suse.de>

> Am 25.01.2013 10:07, schrieb Andreas Färber:
> > Am 25.01.2013 09:19, schrieb Kuo-Jung Su:
> >>  hw/a360.c            |  271 +++++++++++++++++++++++
> >>  hw/a369.c            |  581
> ++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  hw/arm/Makefile.objs |    6 +
> >>  hw/faraday.h         |   21 ++
> >>  4 files changed, 879 insertions(+)
> >>  create mode 100644 hw/a360.c
> >>  create mode 100644 hw/a369.c
> >>  create mode 100644 hw/faraday.h
> >>
> >> diff --git a/hw/a360.c b/hw/a360.c
> >> new file mode 100644
> >> index 0000000..cb0a588
> >> --- /dev/null
> >> +++ b/hw/a360.c
> >> @@ -0,0 +1,271 @@
> >> +/*
> >> + * Faraday A360 Evalution Board
> >> + *
> >> + * Copyright (c) 2012 Faraday Technology
> >> + * Written by Dante Su <dantesu@faraday-tech.com>
> >> + *
> >> + * This code is licensed under GNU GPL v2.
> >
> > Can you please license this and any other files as "v2 or (at your
> > option) any later version"? Cf. http://wiki.qemu.org/Relicensing
> >
> > Also, there is work underway to move target-specific files to the
> > subdirectories of hw/, i.e. suggest the new ARM machine should go to
> > hw/arm/faraday_a360.c as hw/ is terribly crowded today and a360 is
> > pretty generic.
>
> The same applies to the machine names "a360" and "a369" - I feel they
> are too ambiguous, given that there is an AllWinner A20 SoC for
> instance. Can you consider renaming to something less ambiguous like
> "faraday-a360" or so?
>
> Andreas
>
> > For devices it depends on whether they are tightly
> > coupled to the ARM SoC or reusable in any target (x86 etc.).
> >
> > Regards,
> > Andreas
>
> --
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
>
Kuo-Jung Su Jan. 28, 2013, 8:33 a.m. UTC | #7
2013/1/28 Andreas Färber <afaerber@suse.de>

> Am 25.01.2013 09:19, schrieb Kuo-Jung Su:
> > From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >
> > These patches introduce Faraday A36x SoC platform support.
> >
> > Faraday provides ARMv4/ARMv5TE compatible solutions,
> > and focus on ASIC design service.
> >
> > Here are some public documents for you reference.
> >
> > http://www.faraday-tech.com/html/documentation/index.html
> >
> > The pre-built images are also available at my Google Drive:
> >
> > https://docs.google.com/folder/d/0BwfiewvSmUgAX2pTTmtUMGFCZW8/edit
> >
> > Here is the image file list:
> >
> > 1. android-4.0.4/zImage: A369 linux-3.0.31
> > 2. android-4.0.4/romfs-4.0.4.tar.bz2: android-4.0.4
> > 3. nand.img.bz2: A369 nand flash image
> > 4. rom.img.bz2: A369 embedded ROM image
> > 5. u-boot: A369 u-boot-2012.10 ELF file
> > 6. zImage: A369 linux-3.4.12 + initramfs
> > 7. README
>
> Thank you for posting these test images. Could you also publish your
> patches on some public git branch so that one doesn't need to manually
> apply 20 or more patches to test it? (e.g., GitHub, repo.or.cz, ...)
>
> Another thing you could look into is qemu-jeos.git support - could you
> supply configs for building an upstream Linux kernel for testing? You
> can look at arm-vexpress.cfg as template.
>
>
Sorry, there are lot of patches, and most of them have coding styles.
Becuase the entire open source release (I mean 'mine' open source release)
was
initialated 2 weeks ago.
And yes, you might have noticed. The QEMU is my very 1st open source
release....

And there are somehing make things even worst ....
For example:

In u-boot, there are already some bad code / or heavily un-tested code
have release to its git tree.
i.e.
1. The ftsdc010_esdhc contributed by Andes Technology (a subsidiary of
Faraday)
    simply doesn't work at Faraday A369 in u-boot-2013.01.
    One of my colleague has ever make it work in u-boot-2010.09,
    but its performanceis only 1/10 of mine ...

2. The ftgmac100 is somehow contributed by someone should do that with a
    untested version, although it seemds to work correctly with MMU
disabled.

All of these, means after applying my patch, you would have multi-pile
drivers
against the same hardware....

If none of these were problem to you, I'll tried to make them open source
later.

And for a record, in my original open source schedule, the following items
would be release in turn.

1) qemu (a36x)
2) u-boot-2013.01
3) linux-3.4.12
4) falinux (It's a combination of uClinux and build-root, was my personal
    linux BSP, and now seems to be an official one in Faraday)
5) android-4.0.4
6) linux-3.0.31 for android
7) android-dist (A clone of falinux, which is designed to genrated andoird
images)
8) contiki-2.6
9) contiki-2.6-dist (A clone of falinux, which is designed to genrated
contiki images)
10) ecos-3.0
11) ecos-dist (A clone of falinux, which is designed to genrated contiki
images)
12) virgil (A referenced ROM code for my projects, which is also a
RTOS/FreeRTOS)

Because Faraday is actually a ASIC desgin service company, it usualy cares
nothing
about software and intends to make them all open sourced to catch more
customers.

> Changes for v2:
> >
> >    1. coding style fixes (verified with checkpatch.pl)
> >    2. add Faraday A360 support
> >    3. add Faraday USB 2.0 EHCI support
> >    4. merge a369_scu.c into a369.c
> >    5. introduce QOM coding style
> >    6. remove lowercase Macros: min(), max()
> >    7. name all struct as CamelCase style
> >    8. move function prototypes from .c to faraday.h
> >    9. use switch instead of if statement in a369_ahbc_write
> >   10. remove debug prints
> >   11. update all uarts in A36x to DEVICE_LITTLE_ENDIAN.
> >   12. move the variable definitions to the start of the function,
> >       instead of inside a do { } while(0)
> >   13. remove disabled and commented out code.
> >   14. use hw_error() and exit() upon pflash register failed.
> >   15. add const prior to TypeInfo (i.e. static *const*
> >       TypeInfo ftrtc011_info)
> >   16. add le32_to_cpu/cpu_to_le32 to the descriptor processing in
> >       FTGMAC100/FTMAC110.
> >   17. update the GPL license to GPL v2 (except for FTLCDC200,
> >       it's based on pl110.c which is LGPL.)
> >   18. add const to src_* in the DMA controllers (FTAPBBRG020/FTDMAC020)
> >
> >   Note:
> >   1. Thanks to the comments from KONRAD, Andreas, Paul and Blue.
> >      But if there is still something missed, please kindly remind me to
> fix.
> >      Thanks!
>
> Your detailed change log is very helpful, thank you. When you post a v3
> however, please post the patch series as a top-level patchset (i.e., the
> cover letter not as a reply, just the actual patches to the cover
> letter), the change log then should be sufficient to understand its
> historical context and that makes it a little easier for humans or
> Anthony's scripts to find the latest patch versions.
>
>
Sorry, I can't get you very well...
I guess I'm not supposed to use --in-reply-to=<identifier> with git
send-email
and change log should not be removed.
Any way I'll try to find some examples from the email and google for some
more to see how to do that....


> For all your new SysBus devices (i.e., types with .parent =
> SYS_BUS_DEVICE) please use a QOM realizefn instead of a qdev initfn -
> not just the function naming but dc->realize rather than sdc->init. This
> avoids one of us having to go through your code later and doing the
> conversion. (I showed you how to do that for EHCI as an example.)
>
> What I'm still missing in v2 is qtest test cases for the RTC and a
> libqos driver for your I2C master. If you have questions how to go about
> that, feel free to ask on IRC.
>

Sorry, IRC is banned from my company, and I usually don't work at home....
My wife would get crazzy on me.

P.S:
My real work is to help customers to build new their own new SoC platform
and it's extremely easy so I usually have lots of private time at work.


> >   2. There are still two coding style errors reported by checkpatch.pl,
> >      but I think they might be false alarms, here is the error log:
> >
> >   ERROR: need consistent spacing around '*' (ctx:WxV)
> >   #74: FILE: hw/a360.c:32:
> >   +    i2c_bus      *i2c[2];                ^
> >
> >   ERROR: open brace '{' following function declarations go on the next
> line
> >   #4680: FILE: hw/ftlcdc200_template.h:59:
> >   +static drawfn glue(ftlcdc200_draw_fn_, BITS)[48] = {
>
> Yes, your analysis looks correct, you can ignore both "errors".
>

got you, thanks


>
> Regards,
> Andreas
>
> --
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
>
diff mbox

Patch

diff --git a/hw/a369.c b/hw/a369.c
new file mode 100644
index 0000000..cc78351
--- /dev/null
+++ b/hw/a369.c
@@ -0,0 +1,499 @@ 
+/*
+ * Faraday A369 Evalution Board
+ *
+ * Copyright (c) 2012 Faraday Technology
+ *
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+#include "i2c.h"
+#include "boards.h"
+#include "flash.h"
+#include "serial.h"
+#include "ssi.h"
+
+#define A369_NOR_FLASH_ADDR            0x20000000
+#define A369_NOR_FLASH_SIZE            (16 * 1024 * 1024)
+#define A369_NOR_FLASH_SECT_SIZE    (128 * 1024)
+
+#ifndef min
+#define min(a, b)                    ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)                    ((a) > (b) ? (a) : (b))
+#endif
+
+struct a369_ahbc_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    /* HW register cache */
+    uint32_t cr;
+};
+
+struct a369_ddrc_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    
+    /* HW register caches */
+    uint32_t mcr;
+    uint32_t msr;
+};
+
+struct a369_state {
+    ARMCPU *cpu;
+    DeviceState *rom;
+    DeviceState *hdma;    /* AHB DMA */
+    DeviceState *pdma;    /* APB DMA */
+
+    MemoryRegion *as;
+    MemoryRegion *ram;
+    MemoryRegion *ram_alias;
+    MemoryRegion *sram;
+
+    i2c_bus *i2c[2];
+
+    struct a369_ahbc_state ahbc;
+    struct a369_ddrc_state ddrc;
+};
+
+/* ftintc020.c */
+qemu_irq *ftintc020_init(hwaddr base, ARMCPU *cpu);
+
+/* ftgmac100.c */
+void ftgmac100_init(NICInfo *nd, uint32_t base, qemu_irq irq);
+
+/* AHB controller block */
+
+static uint64_t a369_ahbc_read(void *opaque, hwaddr addr, unsigned size)
+{
+    struct a369_state *mach = opaque;
+    struct a369_ahbc_state *s = &mach->ahbc;
+    
+    switch(addr) {
+    case 0x00: return 0x94050000;
+    case 0x04: return 0x96040000;
+    case 0x08: return 0x90f00000;
+    case 0x0c: return 0x92050000;
+    case 0x10: return 0x20080000;
+    case 0x14: return 0xc0080000;
+    case 0x18: return 0x00090000; 
+    case 0x1c: return 0x90000000;
+    case 0x20: return 0x90100000;
+    case 0x24: return 0x90200000;
+    case 0x28: return 0x90300000;
+    case 0x2c: return 0x90400000;
+    case 0x30: return 0x90500000;
+    case 0x34: return 0x90600000;
+    case 0x38: return 0x90700000;
+    case 0x3c: return 0x90800000;
+    case 0x40: return 0x90900000;
+    case 0x44: return 0x90a00000;
+    case 0x48: return 0x90b00000;
+    case 0x4c: return 0x90c00000;
+    case 0x50: return 0x90d00000;
+    case 0x54: return 0x90e00000; 
+    case 0x58: return 0x40080000;
+    case 0x5c: return 0x60080000;
+    case 0x60: return 0xa0000000;
+    case 0x84: return 0x00000001;
+    case 0x88: return s->cr;
+    case 0x8c: return 0x00010301;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static void a369_ahbc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    struct a369_state *mach = opaque;
+    struct a369_ahbc_state *s = &mach->ahbc;
+
+    if (addr == 0x88) {
+        if (!(s->cr & 0x01) && (val & 0x01)) {
+            /* AHB remap */
+            printf("[qemu] a369: AHB remap...\n");
+            sysbus_mmio_map(sysbus_from_qdev(mach->rom), 0, 0x40000000);
+            memory_region_del_subregion(mach->as, mach->ram_alias);
+            memory_region_add_subregion(mach->as, 0x00000000, mach->ram);            
+        }
+        s->cr = (uint32_t)val;
+    }
+}
+
+static const MemoryRegionOps a369_ahbc_ops = {
+    .read  = a369_ahbc_read,
+    .write = a369_ahbc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int a369_ahbc_init(struct a369_state *mach, hwaddr base)
+{
+    struct a369_ahbc_state *s = &mach->ahbc;
+    memory_region_init_io(&s->iomem, &a369_ahbc_ops, mach, "a369_ahbc", 0x1000);
+    memory_region_add_subregion(mach->as, base, &s->iomem);
+    s->cr = 0;
+    return 0;
+}
+
+/* DDRII controller block */
+
+static uint64_t a369_ddrc_read(void *opaque, hwaddr addr, unsigned size)
+{
+    struct a369_state *mach = opaque;
+    struct a369_ddrc_state *s = &mach->ddrc;
+    
+    switch(addr) {
+    case 0x00:
+        return s->mcr;
+    case 0x04:
+        return s->msr;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static void a369_ddrc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    struct a369_state *mach = opaque;
+    struct a369_ddrc_state *s = &mach->ddrc;
+    
+    switch(addr) {
+    case 0x00:
+        s->mcr = (uint32_t)val & 0xffff;
+        break;
+    case 0x04:
+        val = (val & 0x3f) | (s->msr & 0x100);
+        if (!(s->msr & 0x100) && (val & 0x01)) {
+            val &= 0xfffffffe;
+            val |= 0x100;
+            printf("[qemu] a369: ddr init...\n");
+            memory_region_add_subregion(mach->as, 0x10000000, mach->ram_alias);            
+        }
+        s->msr = (uint32_t)val;
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps a369_ddrc_ops = {
+    .read  = a369_ddrc_read,
+    .write = a369_ddrc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int a369_ddrc_init(struct a369_state *mach, hwaddr base)
+{
+    struct a369_ddrc_state *s = &mach->ddrc;
+    
+    memory_region_init_io(&s->iomem, &a369_ddrc_ops, mach, "a369_ddrc", 0x1000);
+    memory_region_add_subregion(mach->as, base, &s->iomem);
+    s->mcr = 0;
+    s->msr = 0;
+    return 0;
+}
+
+/* Board init.  */
+
+static void a369_device_init(struct a369_state *s)
+{
+    qemu_irq *pic;
+    DeviceState *ds;
+    int done_nic = 0;
+    int i;
+    
+    /* Interrupt Controller */
+    pic = ftintc020_init(0x90100000, s->cpu);
+
+    /* Timer */
+    ds = qdev_create(NULL, "ftpwmtmr010");
+    qdev_prop_set_uint32(ds, "freq", 66 * 1000000);
+    qdev_init_nofail(ds);
+    sysbus_mmio_map(sysbus_from_qdev(ds), 0, 0x92300000);
+    sysbus_connect_irq(sysbus_from_qdev(ds), 0, pic[8]);
+    sysbus_connect_irq(sysbus_from_qdev(ds), 1, pic[9]);
+    sysbus_connect_irq(sysbus_from_qdev(ds), 2, pic[10]);
+    sysbus_connect_irq(sysbus_from_qdev(ds), 3, pic[11]);
+
+    /* Serial (FTUART010 which is 16550A compatible) */
+    if (serial_hds[0]) {
+        serial_mm_init(s->as, 
+                       0x92b00000,
+                       2, 
+                       pic[53],
+                       18432000 / 16,
+                       serial_hds[0], 
+                       DEVICE_NATIVE_ENDIAN);
+    }
+    if (serial_hds[1]) {
+        serial_mm_init(s->as,
+                       0x92c00000,
+                       2,
+                       pic[54],
+                       18432000 / 16,
+                       serial_hds[1],
+                       DEVICE_NATIVE_ENDIAN);
+    }
+
+    /* ftscu010 */
+    sysbus_create_simple("a369_scu", 0x92000000, pic[41]);
+    
+    /* ftdmac020 */
+    s->hdma = sysbus_create_simple("ftdmac020", 0x90300000, pic[15]);
+    sysbus_create_simple("ftdmac020", 0x96100000, pic[17]);
+
+    /* ftapbbrg020 */
+    s->pdma = sysbus_create_simple("ftapbbrg020", 0x90f00000, pic[14]);
+
+    /* ftnandc021 */
+    do {
+        qemu_irq ack, req;
+        ds = sysbus_create_simple("ftnandc021", 0x90200000, pic[30]);
+        ack = qdev_get_gpio_in(ds, 0);
+        req = qdev_get_gpio_in(s->hdma, 15);
+        qdev_connect_gpio_out(s->hdma, 15, ack);
+        qdev_connect_gpio_out(ds, 0, req);
+    } while(0);
+
+    /* ftsdc010 */
+#if 0
+    do {
+        qemu_irq ack, req;
+        ds = sysbus_create_simple("ftsdc010", 0x90500000, pic[38]);
+        ack = qdev_get_gpio_in(ds, 0);
+        req = qdev_get_gpio_in(s->hdma, 14);
+        qdev_connect_gpio_out(s->hdma, 14, ack);
+        qdev_connect_gpio_out(ds, 0, req);
+    } while(0);
+#endif
+    do {
+        qemu_irq ack, req;
+        ds = sysbus_create_simple("ftsdc010", 0x90600000, pic[39]);
+        ack = qdev_get_gpio_in(ds, 0);
+        req = qdev_get_gpio_in(s->hdma, 13);
+        qdev_connect_gpio_out(s->hdma, 13, ack);
+        qdev_connect_gpio_out(ds, 0, req);
+    } while(0);
+
+#if 0
+    /* fusbh200 */
+    sysbus_create_simple("faraday-ehci-usb", 0x90800000, pic[36]);
+    
+    /* fotg210 */
+    sysbus_create_simple("faraday-ehci-usb", 0x90900000, pic[37]);
+#endif
+
+    /* ftgmac100 */
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+        if (!done_nic && (!nd->model || strcmp(nd->model, "ftgmac100") == 0)) {
+            ftgmac100_init(nd, 0x90c00000, pic[32]);
+            done_nic = 1;
+        }
+    }
+
+    /* ftrtc011 (only alarm interrupt is connected) */
+    sysbus_create_varargs("ftrtc011", 0x92100000, pic[0],    /* Alarm (Level): NC in A369 */
+                                                  pic[42],    /* Alarm (Edge) */
+                                                  pic[43],    /* Second (Edge) */
+                                                  pic[44],    /* Minute (Edge) */
+                                                  pic[45],    /* Hour (Edge) */
+                                                  NULL);
+    
+    /* ftwdt010 */
+    sysbus_create_simple("ftwdt010", 0x92200000, pic[46]);
+    
+    /* fttsc010 */
+    sysbus_create_simple("fttsc010", 0x92400000, pic[19]);
+    
+    /* ftkbc010 */
+    sysbus_create_simple("ftkbc010", 0x92f00000, pic[21]);
+
+    /* ftlcdc200 */
+    sysbus_create_varargs("ftlcdc200",0x94a00000, pic[0],  /* Global (NC in A369) */
+                                                  pic[25], /* VSTATUS */
+                                                  pic[24], /* Base Address Update */
+                                                  pic[23], /* FIFO Under-Run */
+                                                  pic[22], /* AHB Bus Error */
+                                                  NULL);
+
+    /* fti2c010 */
+    ds = sysbus_create_simple("fti2c010", 0x92900000, pic[51]);
+    s->i2c[0] = (i2c_bus *)qdev_get_child_bus(ds, "i2c");
+    ds = sysbus_create_simple("fti2c010", 0x92A00000, pic[52]);
+    s->i2c[1] = (i2c_bus *)qdev_get_child_bus(ds, "i2c");
+    
+    /* ftssp010 */
+    do {
+        SSIBus *spi;
+        DeviceState *fl;
+        int nr_flash = 1;
+        qemu_irq cs_line;
+        qemu_irq ack, req;
+        
+        ds = qdev_create(NULL, "ftssp010");
+        
+        /* i2s */
+        qdev_prop_set_ptr(ds, "codec_i2c", s->i2c[0]);
+        qdev_init_nofail(ds);
+        sysbus_mmio_map(sysbus_from_qdev(ds), 0, 0x92700000);
+        sysbus_connect_irq(sysbus_from_qdev(ds), 0, pic[49]);
+
+        /* spi */
+        spi = (SSIBus *)qdev_get_child_bus(ds, "spi");
+        for (i = 0; i < nr_flash; i++) {
+            fl = ssi_create_slave_no_init(spi, "m25p80");
+            qdev_prop_set_string(fl, "partname", "w25q64");
+            qdev_init_nofail(fl);
+            cs_line = qdev_get_gpio_in(fl, 0);
+            sysbus_connect_irq(sysbus_from_qdev(ds), i+1, cs_line);
+        }
+        
+        /* DMA (Tx) */
+        ack = qdev_get_gpio_in(ds, 0);
+        req = qdev_get_gpio_in(s->pdma, 7);
+        qdev_connect_gpio_out(s->pdma, 7, ack);
+        qdev_connect_gpio_out(ds, 0, req);
+        
+        /* DMA (Rx) */
+        ack = qdev_get_gpio_in(ds, 1);
+        req = qdev_get_gpio_in(s->pdma, 8);
+        qdev_connect_gpio_out(s->pdma, 8, ack);
+        qdev_connect_gpio_out(ds, 1, req);
+    } while(0);
+
+    /* ftddrII030 */
+    a369_ddrc_init(s, 0x93100000);
+
+    /* ftahbc020 */
+    a369_ahbc_init(s, 0x94000000);
+
+    /* Parallel NOR Flash */
+    do {
+        DriveInfo *dinfo = drive_get_next(IF_PFLASH);
+        if (!pflash_cfi01_register(
+                        A369_NOR_FLASH_ADDR, 
+                        NULL,
+                        "a369.pflash",
+                        A369_NOR_FLASH_SIZE,
+                        dinfo ? dinfo->bdrv : NULL,
+                        A369_NOR_FLASH_SECT_SIZE,
+                        A369_NOR_FLASH_SIZE / A369_NOR_FLASH_SECT_SIZE,
+                        2, 0x0001, 0x227E, 0x2101, 0x0, 0)) {
+            fprintf(stderr, "qemu: Error registering flash memory.\n");
+        }
+    } while(0);
+}
+
+static void a369_board_reset(void *opaque)
+{
+    struct a369_state *s = opaque;
+    
+    if (s->ddrc.msr) {
+        s->ddrc.mcr = 0;
+        s->ddrc.msr = 0;
+        if (s->ahbc.cr) {
+            /* AHB remapped */
+            sysbus_mmio_map(sysbus_from_qdev(s->rom), 0, 0x00000000);
+            memory_region_del_subregion(s->as, s->ram);
+        } else {
+            /* AHB is not yet remapped, but SDRAM is ready */
+            memory_region_del_subregion(s->as, s->ram_alias);
+        }
+        s->ahbc.cr = 0;
+    }
+
+    cpu_reset(CPU(s->cpu));
+}
+
+static void a369_board_init(QEMUMachineInitArgs *args)
+{
+    struct a369_state *s = g_new(struct a369_state, 1);
+
+    s->as = get_system_memory();
+    s->ram  = g_new(MemoryRegion, 1);
+    s->sram = g_new(MemoryRegion, 1);
+
+    /* CPU */
+    if (!args->cpu_model)
+        args->cpu_model = "fa626te";
+
+    s->cpu = cpu_arm_init(args->cpu_model);
+    if (!s->cpu) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    /* A369 supports upto 1GB ram space */
+    if (args->ram_size > 0x40000000)
+        args->ram_size = 0x40000000;
+        
+    printf("qemu: faraday a369 with %dMB ram.\n", args->ram_size >> 20);
+    
+    /* Embedded ROM Init */
+    s->rom = qdev_create(NULL, "rom");    
+    qdev_prop_set_uint32(s->rom, "size", 8192);
+    qdev_init_nofail(s->rom);
+    
+    /* 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);
+    
+    /* RAM Init */
+    memory_region_init_ram(s->ram, "a369.ram", args->ram_size);
+    vmstate_register_ram_global(s->ram);
+    
+    a369_device_init(s);
+    qemu_register_reset(a369_board_reset, s);
+    
+    if (args->kernel_filename) {
+        struct arm_boot_info *bi = g_new(struct arm_boot_info, 1);
+        
+        /* RAM Address Binding */
+        memory_region_add_subregion(s->as, 0x00000000, s->ram);
+        
+        /* Boot Info */
+        memset(bi, 0, sizeof(*bi));
+        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 = 0xa369;
+        arm_load_kernel(s->cpu, bi);
+    } else {
+        /* ROM Address Binding */
+        sysbus_mmio_map(sysbus_from_qdev(s->rom), 0, 0x00000000);
+        /* Partial RAM (before ahb remapped) Address Binding */
+        s->ram_alias = g_new(MemoryRegion, 1);
+        memory_region_init_alias(s->ram_alias, "a369.ram_alias",
+                                 s->ram,
+                                 0,
+                                 min(0x10000000, args->ram_size));
+    }
+}
+
+static QEMUMachine a369_machine = {
+    .name = "a369",
+    .desc = "Faraday A369 (fa626te)",
+    .init = a369_board_init,
+};
+
+static void a369_machine_init(void)
+{
+    qemu_register_machine(&a369_machine);
+}
+
+machine_init(a369_machine_init);
diff --git a/hw/a369_scu.c b/hw/a369_scu.c
new file mode 100644
index 0000000..ee548d4
--- /dev/null
+++ b/hw/a369_scu.c
@@ -0,0 +1,192 @@ 
+/*
+ * QEMU model of the A369 SCU
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Copyright (C) 2012 Dante Su <dantesu@faraday-tech.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "sysemu/sysemu.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq     irq;
+    
+    /* HW register caches */
+    uint32_t general_cfg;
+    uint32_t sclk_cfg0;
+    uint32_t sclk_cfg1;
+    uint32_t mfpsr0;
+    uint32_t mfpsr1;
+
+} a369_scu_state;
+
+static uint64_t
+a369_scu_mem_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    a369_scu_state *s = opaque;
+
+    switch(addr) {
+    case 0x000:
+        return 0x00003369;
+    case 0x004:
+        return 0x00010000;
+    case 0x008:
+        return 0x00000c10;
+    case 0x00c:
+        return 0x00000230;
+    case 0x010:
+        return 0x00000083;
+    case 0x014:
+        return 0x00000100;
+    case 0x01C:
+        return 0x00000003;
+    case 0x020:
+        return 0x20010003;
+    case 0x024:
+        return 0x00000003;
+    case 0x060:
+        return 0x00280028;
+    case 0x200:
+        return s->general_cfg;
+    case 0x204:
+        return 0x00001cc8;
+    case 0x228:
+        return s->sclk_cfg0;
+    case 0x22c:
+        return s->sclk_cfg1;
+    case 0x230:
+        return 0x00003fff;
+    case 0x238:
+        return s->mfpsr0;
+    case 0x23c:
+        return s->mfpsr1;
+    case 0x240:
+        return 0x11111111;
+    case 0x244:
+        return 0x11111111;
+    case 0x254:
+        return 0x00000303;
+    case 0x258:
+        return 0x8000007f;
+    }
+
+    return 0;
+}
+
+static void
+a369_scu_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size)
+{
+    a369_scu_state *s = opaque;
+    
+    switch(addr) {
+    case 0x200:
+        s->general_cfg = (uint32_t)val;
+        break;
+    case 0x228:
+        s->sclk_cfg0 = (uint32_t)val;
+        break;
+    case 0x22c:
+        s->sclk_cfg1 = (uint32_t)val;
+        break;
+    case 0x238:
+        s->mfpsr0 = (uint32_t)val;
+        break;
+    case 0x23c:
+        s->mfpsr1 = (uint32_t)val;
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps bus_ops = {
+    .read  = a369_scu_mem_read,
+    .write = a369_scu_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void a369_scu_reset(DeviceState *d)
+{
+    a369_scu_state *s = DO_UPCAST(a369_scu_state, busdev.qdev, d);
+    
+    s->general_cfg = 0x00001078;
+    s->sclk_cfg0   = 0x26877330;
+    s->sclk_cfg1   = 0x000a0a0a;
+    s->mfpsr0      = 0x00000241;
+    s->mfpsr1      = 0x00000000;
+}
+
+static int a369_scu_init(SysBusDevice *dev)
+{
+    a369_scu_state *s = FROM_SYSBUS(typeof(*s), dev);
+    
+    memory_region_init_io(&s->iomem, &bus_ops, s, "a369_scu", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_a369_scu = {
+    .name = "a369_scu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(general_cfg, a369_scu_state),
+        VMSTATE_UINT32(sclk_cfg0, a369_scu_state),
+        VMSTATE_UINT32(sclk_cfg1, a369_scu_state),
+        VMSTATE_UINT32(mfpsr0, a369_scu_state),
+        VMSTATE_UINT32(mfpsr1, a369_scu_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void a369_scu_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    sdc->init  = a369_scu_init;
+    k->vmsd    = &vmstate_a369_scu;
+    k->reset   = a369_scu_reset;
+    k->no_user = 1;
+}
+
+static TypeInfo a369_scu_info = {
+    .name           = "a369_scu",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(a369_scu_state),
+    .class_init     = a369_scu_class_init,
+};
+
+static void a369_scu_register_types(void)
+{
+    type_register_static(&a369_scu_info);
+}
+
+type_init(a369_scu_register_types)
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 6d049e7..4cc85e5 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,4 +1,10 @@ 
 obj-y = integratorcp.o versatilepb.o arm_pic.o
+obj-y += a369.o a369_scu.o \
+				rom.o ftdmac020.o ftapbbrg020.o \
+				ftintc020.o fttmr010.o ftpwmtmr010.o \
+				ftspi020.o ftssp010.o fti2c010.o \
+				ftrtc011.o ftwdt010.o ftmac110.o ftgmac100.o ftlcdc200.o \
+				fttsc010.o ftkbc010.o ftnandc021.o ftsdc010.o
 obj-y += arm_boot.o
 obj-y += xilinx_zynq.o zynq_slcr.o
 obj-y += xilinx_spips.o