qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 02/20] arm: add Faraday a369 SoC platform sup


From: Kuo-Jung Su
Subject: Re: [Qemu-devel] [PATCH v3 02/20] arm: add Faraday a369 SoC platform support
Date: Mon, 18 Feb 2013 11:28:07 +0800

2013/2/8 Igor Mitsyanko <address@hidden>
>
>
> On 02/06/2013 01:45 PM, 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         |    1 +
>  hw/arm/faraday_a369.c        |  161 +++++++++++++++++++++++++++++
>  hw/arm/faraday_a369_keypad.c |  234 
> ++++++++++++++++++++++++++++++++++++++++++
>  hw/arm/faraday_a369_scu.c    |  188 +++++++++++++++++++++++++++++++++
>  hw/arm/ftkbc010.h            |   26 +++++
>  5 files changed, 610 insertions(+)
>  create mode 100644 hw/arm/faraday_a369.c
>  create mode 100644 hw/arm/faraday_a369_keypad.c
>  create mode 100644 hw/arm/faraday_a369_scu.c
>  create mode 100644 hw/arm/ftkbc010.h
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 59d7023..02d1a7b 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -34,3 +34,4 @@ obj-$(CONFIG_FDT) += ../device_tree.o
>
>  obj-y := $(addprefix ../,$(obj-y))
>  obj-y += faraday_a360.o faraday_a360_pmu.o
> +obj-y += faraday_a369.o faraday_a369_scu.o faraday_a369_keypad.o
> diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
> new file mode 100644
> index 0000000..e32dc7f
> --- /dev/null
> +++ b/hw/arm/faraday_a369.c
> @@ -0,0 +1,161 @@
> +/*
> + * 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/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"
> +
> +typedef FaradayMachState    A369State;
> +
> +/* Board init.  */
> +
> +static void
> +a369_device_init(A369State *s)
> +{
> +    /* Serial (FTUART010 which is 16550A compatible) */
> +    if (serial_hds[0]) {
> +        serial_mm_init(s->as,
> +                       0x92b00000,
> +                       2,
> +                       NULL,
> +                       18432000 / 16,
> +                       serial_hds[0],
> +                       DEVICE_LITTLE_ENDIAN);
> +    }
> +    if (serial_hds[1]) {
> +        serial_mm_init(s->as,
> +                       0x92c00000,
> +                       2,
> +                       NULL,
> +                       18432000 / 16,
> +                       serial_hds[1],
> +                       DEVICE_LITTLE_ENDIAN);
> +    }
> +
> +    /* ftscu010 */
> +    s->scu = sysbus_create_simple("a369.scu", 0x92000000, NULL);
> +
> +    /* ftkbc010 */
> +    sysbus_create_simple("a369.keypad", 0x92f00000, NULL);
> +}
> +
> +static void
> +a369_board_init(QEMUMachineInitArgs *args)
> +{
> +    DriveInfo *dinfo;
> +    struct arm_boot_info *bi = NULL;
> +    A369State *s = g_new(A369State, 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) {
> +        args->cpu_model = "arm926";
> +        s->cpu = cpu_arm_init(args->cpu_model);
> +        if (!s->cpu) {
> +            hw_error("a369: Unable to find CPU definition\n");
> +            exit(1);
> +        }
> +    }
> +
> +    s->ahb_slave4 = 0x00080000; /* ROM: base=0x00000000, size=256MB */
> +    s->ahb_slave6 = 0x10090000; /* RAM: base=0x10000000, size=512MB */
>
>
> Does this register provide information on max allowable RAM size or amount of 
> RAM actually accessible in a system? I mean,
> should this register be modified accordingly if args->ram_size value is less 
> then 512MB?
>
>

Yes, the values to the registers define both the base address and max. size
to the corresponding salve devices.

Although these registers are all R/W, they should be treated as read-only to
the softwares.
Modifying the setting to slave devices would alter the system memory mapped
and might cause un-predictable issues.

P.S:
These registers are designed to be writable for Faraday internal test only.
Sometimes we'll have A36x mounted with a new external AHB daughter board
with built-in CPU and peripheral, and make A36X  as an expansion bus.

Only in such case, we'll update the AHB slave settings for FPGA test.

> +
> +    /* A369 supports upto 512MB ram space */
> +    if (args->ram_size > 0x20000000) {
> +        args->ram_size = 0x20000000;
> +    }
>
> +
> +    /* Use parallel NOR flash for ROM emulation */
> +    dinfo = drive_get_next(IF_PFLASH);
> +    s->rom = pflash_cfi01_register(
> +                    0,      /* base address */
> +                    NULL,
> +                    "a369.rom",
> +                    6144,   /* 6 KB */
> +                    dinfo ? dinfo->bdrv : NULL,
>
>
> I think you should also consider a case when we're booting with bootstrap 
> code in ROM (no kernel_image specified). Right now,
> if no rom image is specified, QEMU will abort with "trying to execute code 
> outside RAM" error. You could check for this case here
> and abort QEMU with a more descriptive error.
>

got it, thanks

>
> +                    1024,   /* 1 KB sector */
> +                    6,      /* 6 sector per chip */
> +                    4,      /* 32 bits */
> +                    0, 0, 0, 0, /* id */
> +                    0       /* Little Endian */);
> +    if (!s->rom) {
> +        hw_error("a369: failed to init ROM device.\n");
> +        exit(1);
> +    }
> +
> +    /* 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);
> +
> +    if (args->kernel_filename) {
> +        bi = g_new0(struct arm_boot_info, 1);
> +
> +        /* RAM Address Binding */
> +        memory_region_add_subregion(s->as, 0x00000000, s->ram);
> +
>
>
> pflash_cfi01_register() already mapped ROM at address 0x0, this line causes 
> both RAM and ROM to be mapped
> at 0x0. You should unmap ROM first.
> Even though we have memory_region_add_subregion() and 
> memory_region_add_subregion_overlap(), looks like currently there is no 
> difference in behaviour
> of memregions initialised with either of these two functions.
>
>

Got it, thanks
>
> +        /* Boot Info */
> +        bi->ram_size = args->ram_size;
> +        bi->kernel_filename = args->kernel_filename;
> +        bi->kernel_cmdline = args->kernel_cmdline;
> +        bi->initrd_filename = args->initrd_filename;
> +        bi->board_id = 0xa369;
> +        arm_load_kernel(s->cpu, bi);
>
>
> So, I assume this case models operation just after debootstrap loaded uboot 
> (or kernel) into memory and remapped ROM and RAM?
> Shouldn't you set ahb_remapped and ddr_inited here then, or uboot/kernel will 
> do it anyway?
>
>

Yes, both the ahb_remapped and ddr_inited should be set here.
The u-boot/linux-kernel would never do the AHB remap, instead the bootstrap
would do it for them.

> +    } else {
> +        /* ROM Address Binding */
> +        sysbus_mmio_map(SYS_BUS_DEVICE(s->rom), 0, 0x00000000);
> +        /* Partial RAM (before ahb remapped) Address Binding */
> +        s->ram_alias = g_new(MemoryRegion, 1);
> +        /* The address window is restricted to 256MB before remap */
> +        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,
> +    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_keypad.c b/hw/arm/faraday_a369_keypad.c
> new file mode 100644
> index 0000000..0983d7e
> --- /dev/null
> +++ b/hw/arm/faraday_a369_keypad.c
> @@ -0,0 +1,234 @@
> +/*
> + * 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 <qemu/timer.h>
> +#include <sysemu/sysemu.h>
> +
> +#include "ftkbc010.h"
> +
> +/* 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;
> +
> +    int x;
> +    int y;
> +
> +    /* HW registers */
> +    uint32_t cr;
> +    uint32_t isr;
> +} Ftkbc010State;
> +
> +#define FTKBC010(obj) \
> +    OBJECT_CHECK(Ftkbc010State, obj, TYPE_FTKBC010)
> +
> +static void ftkbc010_update(Ftkbc010State *s)
> +{
> +    uint32_t ier = 0;
> +
> +    /* keypad interrupt */
> +    ier |= (s->cr & (1 << 8)) ? (1 << 2) : 0;
> +    /* tx interrupt */
> +    ier |= (s->cr & (1 << 3)) ? (1 << 1) : 0;
> +    /* rx interrupt */
> +    ier |= (s->cr & (1 << 4)) ? (1 << 0) : 0;
> +
> +    if (ier & s->isr) {
> +        qemu_irq_raise(s->irq);
> +    } else {
> +        qemu_irq_lower(s->irq);
> +    }
> +}
> +
> +static uint64_t ftkbc010_mem_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    Ftkbc010State *s = FTKBC010(opaque);
> +
> +    switch (addr) {
> +    case REG_CR:
> +        return s->cr;
> +    case REG_ISR:
> +        return s->isr;
> +    case REG_KPDXR:
> +        return ~(1 << s->x);
> +    case REG_KPDYR:
> +        return ~(1 << s->y);
> +    case REG_REVR:
> +        return 0x00010403;  /* rev 1.4.3 */
> +    case REG_FEAR:
> +        return 0x00000808;  /* 8x8 scan code for keypad */
> +    default:
> +        break;
> +    }
> +
> +    return 0;
> +}
> +
> +static void ftkbc010_mem_write(void    *opaque,
> +                               hwaddr   addr,
> +                               uint64_t val,
> +                               unsigned size)
> +{
> +    Ftkbc010State *s = FTKBC010(opaque);
> +
> +    switch (addr) {
> +    case REG_CR:
> +        s->cr = (uint32_t)val;
> +        /* if ftkbc010 enabled */
> +        if (!(s->cr & (1 << 2))) {
> +            break;
> +        }
> +        /* if keypad interrupt cleared */
> +        if (s->cr & (1 << 10)) {
> +            s->cr &= ~(1 << 10);
> +            s->isr &= ~(1 << 2);
> +        }
> +        /* if rx interrupt cleared */
> +        if (s->cr & (1 << 7)) {
> +            s->cr &= ~(1 << 7);
> +            s->isr &= ~(1 << 0);
> +        }
> +        /* if tx interrupt cleared */
> +        if (s->cr & (1 << 6)) {
> +            s->cr &= ~(1 << 6);
> +            s->isr &= ~(1 << 1);
> +        }
> +        ftkbc010_update(s);
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps ftkbc010_mem_ops = {
> +    .read  = ftkbc010_mem_read,
> +    .write = ftkbc010_mem_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void ftkbc010_key_event(void *opaque, int scancode)
> +{
> +    Ftkbc010State *s = FTKBC010(opaque);
> +    int released = 0;
> +
> +    /* key release from qemu */
> +    if (scancode & 0x80) {
> +        released = 1;
> +    }
> +
> +    /* strip qemu key release bit */
> +    scancode &= ~0x80;
> +
> +    /* keypad interrupt */
> +    if (!released && (s->cr & (1 << 8))) {
> +        switch (scancode) {
> +        case KEYCODE_ESC:
> +        case KEYCODE_BACKSPACE:
> +            s->x = 1;
> +            break;
> +        case KEYCODE_ENTER:
> +        case KEYCODE_MENU:
> +        case KEYCODE_SPACE:
> +            s->x = 3;
> +            break;
> +        default:
> +            s->x = 2;    /* KEY_HOME */
> +            break;
> +        }
> +        s->y = 0;
> +        s->isr |= (1 << 2);
> +        ftkbc010_update(s);
> +    }
> +}
> +
> +static void ftkbc010_reset(DeviceState *ds)
> +{
> +    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
> +    Ftkbc010State *s = FTKBC010(FROM_SYSBUS(Ftkbc010State, busdev));
> +
> +    qemu_irq_lower(s->irq);
> +}
> +
> +static int ftkbc010_init(SysBusDevice *dev)
> +{
> +    Ftkbc010State *s = FTKBC010(FROM_SYSBUS(Ftkbc010State, dev));
> +
> +    s->cr  = 0;
> +    s->isr = 0;
> +    s->x   = 0;
> +    s->y   = 0;
> +
> +    memory_region_init_io(&s->iomem,
> +                          &ftkbc010_mem_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(cr, Ftkbc010State),
> +        VMSTATE_UINT32(isr, Ftkbc010State),
> +        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..b1c34e8
> --- /dev/null
> +++ b/hw/arm/faraday_a369_scu.c
> @@ -0,0 +1,188 @@
> +/*
> + * 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 <ui/console.h>
> +#include <qemu/timer.h>
> +#include <sysemu/sysemu.h>
> +
> +#include "faraday.h"
> +
> +#define REG_CHIPID      0x000   /* SoC chip id */
> +#define REG_REVISON     0x004   /* SCU revision */
> +#define REG_HWCFG       0x008   /* HW configuration strap */
> +#define REG_PLL1CR      0x020   /* PLL1 control register */
> +#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_MFPINMUX0   0x238   /* Multi-function pinmux 0 */
> +#define REG_MFPINMUX1   0x23C   /* Multi-function pinmux 1 */
> +
> +#define TYPE_A369SCU    "a369.scu"
> +
> +typedef struct A369SCUState {
> +    SysBusDevice busdev;
> +    MemoryRegion iomem;
> +
> +    /* HW registers */
> +    uint32_t general_cfg;
> +    uint32_t sclk_cfg0;
> +    uint32_t sclk_cfg1;
> +    uint32_t mfpsr0;
> +    uint32_t mfpsr1;
> +} A369SCUState;
> +
> +#define A369SCU(obj) \
> +    OBJECT_CHECK(A369SCUState, obj, TYPE_A369SCU)
> +
> +static uint64_t
> +a369scu_mem_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    A369SCUState *s = A369SCU(opaque);
> +    uint64_t ret = 0;
> +
> +    switch (addr) {
> +    case REG_CHIPID:
> +        ret = 0x00003369;   /* FIE3369 = A369 */
> +        break;
> +    case REG_REVISON:
> +        ret = 0x00010000;
> +        break;
> +    case REG_HWCFG:
> +        ret = 0x00000c10;
> +        break;
> +    case REG_PLL1CR:
> +        ret = 0x20010003;
> +        break;
> +    case REG_GPINMUX:
> +        ret = s->general_cfg;
> +        break;
> +    case REG_EXTHWCFG:
> +        ret = 0x00001cc8;
> +        break;
> +    case REG_CLKCFG0:
> +        ret = s->sclk_cfg0;
> +        break;
> +    case REG_CLKCFG1:
> +        ret = s->sclk_cfg1;
> +        break;
> +    case REG_MFPINMUX0:
> +        ret = s->mfpsr0;
> +        break;
> +    case REG_MFPINMUX1:
> +        ret = s->mfpsr1;
> +        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:
> +        s->general_cfg = (uint32_t)val;
> +        break;
> +    case REG_CLKCFG0:
> +        s->sclk_cfg0 = (uint32_t)val;
> +        break;
> +    case REG_CLKCFG1:
> +        s->sclk_cfg1 = (uint32_t)val;
> +        break;
> +    case REG_MFPINMUX0:
> +        s->mfpsr0 = (uint32_t)val;
> +        break;
> +    case REG_MFPINMUX1:
> +        s->mfpsr1 = (uint32_t)val;
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps a369scu_mem_ops = {
> +    .read  = a369scu_mem_read,
> +    .write = a369scu_mem_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void a369scu_reset(DeviceState *ds)
> +{
> +    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
> +    A369SCUState *s = A369SCU(FROM_SYSBUS(A369SCUState, busdev));
> +
> +    s->general_cfg = 0x00001078;
> +    s->sclk_cfg0   = 0x26877330;
> +    s->sclk_cfg1   = 0x000a0a0a;
> +    s->mfpsr0      = 0x00000241;
> +    s->mfpsr1      = 0x00000000;
> +}
> +
> +static int a369scu_init(SysBusDevice *dev)
> +{
> +    A369SCUState *s = A369SCU(FROM_SYSBUS(A369SCUState, dev));
> +
> +    memory_region_init_io(&s->iomem,
> +                          &a369scu_mem_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(general_cfg, A369SCUState),
> +        VMSTATE_UINT32(sclk_cfg0, A369SCUState),
> +        VMSTATE_UINT32(sclk_cfg1, A369SCUState),
> +        VMSTATE_UINT32(mfpsr0, A369SCUState),
> +        VMSTATE_UINT32(mfpsr1, A369SCUState),
> +        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/ftkbc010.h b/hw/arm/ftkbc010.h
> new file mode 100644
> index 0000000..5d25ffa
> --- /dev/null
> +++ b/hw/arm/ftkbc010.h
> @@ -0,0 +1,26 @@
> +/*
> + * 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 */
> +
> +#endif
>
>



--
Best wishes,
Kuo-Jung Su



reply via email to

[Prev in Thread] Current Thread [Next in Thread]