From: Anthony Liguori <anthony@codemonkey.ws>
To: Peter Chubb <peter.chubb@nicta.com.au>
Cc: Peter Maydell <peter.maydell@linaro.org>,
hsjang@ok-labs.com, qemu-devel@nongnu.org, philipo@ok-labs.com,
adamc@ok-labs.com
Subject: Re: [Qemu-devel] [PATCH] Add KZM board support to qemu
Date: Fri, 23 Sep 2011 09:38:58 -0500 [thread overview]
Message-ID: <4E7C9A02.7000906@codemonkey.ws> (raw)
In-Reply-To: <w4wrd0xesn.wl%peter@chubb.wattle.id.au>
On 09/22/2011 07:50 PM, Peter Chubb wrote:
>
>
> The KZM board is an evaluation board for the ARM v6 i.mx31 processor.
> It is about the only readily-available development board for that
> processor, even though the imx.31 is used in many embedded devices.
>
> This patch was developed at OK-Labs. I have permission from them to
> push it upstream.
>
>
>
> Signed-Off-By: Peter Chubb<peter.chubb@nicta.com.au>
> Signed-Off-By: Hans Jang<hsjang@ok-labs.com>
> Signed-off-by: Adam Clench<adamc@ok-labs.com>
Peter,
Could you bring this through your tree if appropriate? Thanks.
Regards,
Anthony Liguori
> ---
> Makefile.target | 1 +
> hw/imx-int.c | 155 ++++++++++++++++++++++++
> hw/imx-serial.c | 195 ++++++++++++++++++++++++++++++
> hw/imx-timer.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> hw/imx.h | 14 ++
> hw/kzm.c | 86 +++++++++++++
> hw/kzm.h | 5 +
> 7 files changed, 811 insertions(+), 0 deletions(-)
> create mode 100644 hw/imx-int.c
> create mode 100644 hw/imx-serial.c
> create mode 100644 hw/imx-timer.c
> create mode 100644 hw/imx.h
> create mode 100644 hw/kzm.c
> create mode 100644 hw/kzm.h
>
> diff --git a/Makefile.target b/Makefile.target
> index 88d2f1f..e24dda8 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -331,6 +331,7 @@ endif
> obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
> obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
> obj-arm-y += versatile_pci.o
> +obj-arm-y += kzm.o imx-int.o imx-serial.o imx-timer.o
> obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
> obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
> obj-arm-y += pl061.o
> diff --git a/hw/imx-int.c b/hw/imx-int.c
> new file mode 100644
> index 0000000..9674112
> --- /dev/null
> +++ b/hw/imx-int.c
> @@ -0,0 +1,155 @@
> +/*
> + * IMX31 Interrupt Controller
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans Jang
> + *
> + * This code is licenced under the GPL.
> + */
> +
> +#include "imx.h"
> +
> +//#define DEBUG_INT
> +#ifdef DEBUG_INT
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_int: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while(0)
> +#endif
> +
> +
> +#define IMX_INT_NUM_IRQS 64
> +
> +typedef struct {
> + uint32_t base;
> + uint32_t level;
> +
> + char pending[IMX_INT_NUM_IRQS];
> + char enable[IMX_INT_NUM_IRQS];
> + uint32_t intcntl;
> +
> + qemu_irq irq;
> +} imx_int_state;
> +
> +
> +/* Update interrupts. */
> +static void imx_int_update(imx_int_state *s)
> +{
> + int new_level = 0;
> + int i;
> + for(i = 0; i< IMX_INT_NUM_IRQS; ++i) {
> + if (s->pending[i]&& s->enable[i]) {
> + new_level = 1;
> + break;
> + }
> + }
> +
> + if (s->level != new_level) {
> + DPRINTF("irq=%d, level=%d\n", i, new_level);
> + qemu_set_irq(s->irq, new_level);
> + s->level = new_level;
> + }
> +}
> +
> +static void imx_int_set_irq(void *opaque, int irq, int level)
> +{
> + imx_int_state *s = (imx_int_state *)opaque;
> + s->pending[irq] = level;
> + imx_int_update(s);
> +}
> +
> +
> +static uint32_t imx_int_read(void *opaque, target_phys_addr_t offset)
> +{
> + imx_int_state *s = (imx_int_state *)opaque;
> + int i;
> +
> + DPRINTF("read(offset = 0x%x)\n", offset>> 2);
> + switch (offset>> 2) {
> + case 0: /* INTCNTL */
> + return s->intcntl;
> + case 16: /* nivecsr : pending interrupt */
> + for(i = 0; i< IMX_INT_NUM_IRQS; ++i) {
> + if (s->pending[i]&& s->enable[i]) {
> + imx_int_set_irq(opaque, i, 0);
> + //printf("return pending interrupt = irq = %d\n", i);
> + return i<< 16;
> + }
> + }
> + return 0xFFFF<<16;
> + default:
> + cpu_abort (cpu_single_env, "imx_int_read: Bad offset %x\n", (int)offset);
> + return 0;
> + }
> +}
> +
> +static void imx_int_write(void *opaque, target_phys_addr_t offset, uint32_t val)
> +{
> + imx_int_state *s = (imx_int_state *)opaque;
> +
> + DPRINTF("write(0x%x) = %x\n", offset>>2, val);
> + switch (offset>> 2) {
> + case 0: /* INTCNTL */
> + s->intcntl = val;
> + break;
> + case 2: /* INTENABLE */
> + DPRINTF("enable(%d)\n",val);
> + s->enable[val] = 1;
> + break;
> + case 3: /* INTDISABLE */
> + s->enable[val] = 0;
> + DPRINTF("disabled(%d)\n",val);
> + imx_int_update(s);
> + break;
> + case 4: /* intenableh */
> + break;
> + case 5: /* intenablel */
> + break;
> + case 6: /* inttypeh */
> + break;
> + case 7: /* inttypel */
> + case 8: /* NIPRIORITY */
> + case 9:
> + case 10:
> + case 11:
> + case 12:
> + case 13:
> + case 14:
> + case 15:
> + /* ignore */
> + break;
> + default:
> + cpu_abort(cpu_single_env, "imx_int_write: Bad offset %x\n", (int)offset);
> + return;
> + }
> + imx_int_update(s);
> +}
> +
> +static CPUReadMemoryFunc *imx_int_readfn[] = {
> + imx_int_read,
> + imx_int_read,
> + imx_int_read
> +};
> +
> +static CPUWriteMemoryFunc *imx_int_writefn[] = {
> + imx_int_write,
> + imx_int_write,
> + imx_int_write
> +};
> +
> +qemu_irq *imx_int_init(uint32_t base, qemu_irq irq)
> +{
> + imx_int_state *s;
> + qemu_irq *qi;
> + int iomemtype;
> +
> + s = (imx_int_state *)g_malloc0(sizeof *s);
> + iomemtype = cpu_register_io_memory(imx_int_readfn,
> + imx_int_writefn, s, DEVICE_NATIVE_ENDIAN);
> + cpu_register_physical_memory(base, 0x00001000, iomemtype);
> + qi = qemu_allocate_irqs(imx_int_set_irq, s, 64);
> + s->base = base;
> + s->irq = irq;
> + /* ??? Save/restore. */
> + return qi;
> +}
> diff --git a/hw/imx-serial.c b/hw/imx-serial.c
> new file mode 100644
> index 0000000..d14474d
> --- /dev/null
> +++ b/hw/imx-serial.c
> @@ -0,0 +1,195 @@
> +/*
> + * IMX31 Interrupt Controller
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.
> + */
> +
> +#include "imx.h"
> +#include "qemu-char.h"
> +
> +//#define DEBUG_SERIAL
> +#ifdef DEBUG_SERIAL
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_serial: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while(0)
> +#endif
> +
> +typedef struct {
> + uint32_t base;
> + int32_t readbuff;
> +
> + uint32_t usr1;
> + uint32_t usr2;
> + uint32_t ucr1;
> + uint32_t uts1;
> +
> + qemu_irq irq;
> + CharDriverState *chr;
> +} imx_state;
> +
> +#define USR1_TRDY 0x2000 /* Xmitter ready */
> +#define USR1_RRDY 0x200 /* receiver ready */
> +
> +#define USR2_TXFE 0x4000
> +#define USR2_RDR 0x1
> +#define USR2_TXDC 0x8
> +
> +#define UCR1_RRDYEN 0x200
> +#define UCR1_TRDYEN 0x2000
> +
> +#define UTS1_TXFULL 0x10
> +#define UTS1_RXEMPTY 0x20
> +
> +static void imx_update(imx_state *s)
> +{
> + uint32_t flags;
> + flags = (s->usr1& s->ucr1);
> + qemu_set_irq(s->irq, !!flags);
> +}
> +
> +static uint32_t imx_read(void *opaque, target_phys_addr_t offset)
> +{
> + imx_state *s = (imx_state *)opaque;
> + uint32_t c;
> +
> + DPRINTF("read(offset=%x)\n", offset>> 2);
> + switch (offset>> 2) {
> + case 0x0: /* URXD */
> + c = s->readbuff;
> + s->usr1&= ~USR1_RRDY;
> + s->usr2&= ~USR2_RDR;
> + s->uts1 |= UTS1_RXEMPTY;
> + imx_update(s);
> + qemu_chr_accept_input(s->chr);
> + return c;
> + case 0x25: /* USR1 */
> + imx_update(s);
> + return s->usr1;
> + case 0x26: /* USR2 */
> + imx_update(s);
> + return s->usr2;
> +
> + case 0x20: /* UCR1 */
> + return s->ucr1;
> + case 0x2d: /* UTS1 */
> + return s->uts1;
> +
> + case 0x21: /* UCR2 */
> + case 0x22: /* UCR3 */
> + case 0x23: /* UCR4 */
> + case 0x24: /* UFCR */
> + return 0x0; /* TODO */
> +
> + default:
> + cpu_abort (cpu_single_env, "imx_read: Bad offset %x\n", (int)offset);
> + return 0;
> + }
> +}
> +
> +
> +static void imx_write(void *opaque, target_phys_addr_t offset,
> + uint32_t value)
> +{
> + imx_state *s = (imx_state *)opaque;
> + unsigned char ch;
> +
> + DPRINTF("write(offset=%x, value = %x)\n", offset>> 2, value);
> + switch (offset>> 2) {
> + case 0x10: /* UTXD */
> + ch = value;
> + if (s->chr)
> + qemu_chr_fe_write(s->chr,&ch, 1);
> + // XXX imx_update(s);
> + break;
> +
> + case 0x20: /* UCR1 */
> + s->ucr1 = value;
> + DPRINTF("write(ucr1=%x)\n", value);
> + imx_update(s);
> + break;
> +
> + case 0x21: /* UCR2 */
> + case 0x22: /* UCR3 */
> + case 0x23: /* UCR4 */
> + case 0x24: /* UFCR */
> + case 0x25: /* USR1 */
> + case 0x29: /* UBIR */
> + case 0x2a: /* UBMR */
> + case 0x2c: /* BIPR1 */
> + /* TODO */
> + break;
> +
> + default:
> + cpu_abort (cpu_single_env, "imx_write: Bad offset %x\n", (int)offset);
> + }
> +}
> +
> +static int imx_can_receive(void *opaque)
> +{
> + imx_state *s = (imx_state *)opaque;
> + return !(s->usr1& USR1_RRDY);
> +}
> +
> +static void imx_put_data(void *opaque, uint32_t value)
> +{
> + imx_state *s = (imx_state *)opaque;
> +
> + s->usr1 |= USR1_RRDY;
> + s->usr2 |= USR2_RDR;
> + s->uts1&= ~UTS1_RXEMPTY;
> + s->readbuff = value;
> + imx_update(s);
> +}
> +
> +static void imx_receive(void *opaque, const uint8_t *buf, int size)
> +{
> + imx_put_data(opaque, *buf);
> +}
> +
> +static void imx_event(void *opaque, int event)
> +{
> + if (event == CHR_EVENT_BREAK)
> + imx_put_data(opaque, 0x400);
> +}
> +
> +static CPUReadMemoryFunc *imx_readfn[] = {
> + imx_read,
> + imx_read,
> + imx_read
> +};
> +
> +static CPUWriteMemoryFunc *imx_writefn[] = {
> + imx_write,
> + imx_write,
> + imx_write
> +};
> +
> +void imx_serial_init(uint32_t base, qemu_irq irq, CharDriverState *chr)
> +{
> + int iomemtype;
> + imx_state *s;
> +
> + s = (imx_state *)g_malloc0(sizeof(imx_state));
> + iomemtype = cpu_register_io_memory(imx_readfn,
> + imx_writefn, s, DEVICE_NATIVE_ENDIAN);
> + cpu_register_physical_memory(base, 0x00001000, iomemtype);
> +
> + s->irq = irq;
> + s->usr1 = USR1_TRDY;
> + s->usr2 = USR2_TXFE | USR2_TXDC;
> + s->ucr1 = UCR1_TRDYEN | UCR1_RRDYEN;
> + s->uts1 = UTS1_RXEMPTY;
> + s->readbuff = -1;
> + s->base = base;
> + s->chr = chr;
> + if (chr){
> + qemu_chr_add_handlers(chr, imx_can_receive, imx_receive,
> + imx_event, s);
> + }
> + /* ??? Save/restore. */
> +}
> +
> diff --git a/hw/imx-timer.c b/hw/imx-timer.c
> new file mode 100644
> index 0000000..65a4b28
> --- /dev/null
> +++ b/hw/imx-timer.c
> @@ -0,0 +1,355 @@
> +/*
> + * IMX31 Timer
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.
> + */
> +
> +#include "imx.h"
> +#include "qemu-timer.h"
> +
> +//#define DEBUG_TIMER
> +#ifdef DEBUG_TIMER
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_timer: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while(0)
> +#endif
> +
> +/*
> + * GPT : General purpose timer
> + */
> +
> +#define TIMER_MAX 0xFFFFFFFF
> +#define GPT_FREQ 50000000
> +#define GPT_CR_EN (1<< 0)
> +#define GPT_SR_OF1 (1<< 0)
> +#define GPT_SR_ROV (1<< 5)
> +#define GPT_IR_OF1IE (1<< 0)
> +#define GPT_IR_ROVIE (1<< 5)
> +
> +typedef struct {
> + uint32_t base;
> + QEMUTimer *timer;
> + uint32_t cr;
> + uint32_t sr;
> + uint32_t pr;
> + uint32_t ir;
> + uint32_t ocr1;
> + uint32_t cnt;
> +
> + int waiting_rov;
> + qemu_irq irq;
> +} imxg_timer_state;
> +
> +/* Check all active timers, and schedule the next timer interrupt. */
> +static void imxg_timer_update(imxg_timer_state *s)
> +{
> + /* Update interrupts. */
> + if ((s->cr& GPT_CR_EN)
> +&& (((s->sr& GPT_SR_OF1)&& (s->ir& GPT_IR_OF1IE)) ||
> + ((s->sr& GPT_SR_ROV)&& (s->ir& GPT_IR_ROVIE)))) {
> + qemu_irq_raise(s->irq);
> + } else {
> + qemu_irq_lower(s->irq);
> + }
> +}
> +
> +static uint64_t imxg_timer_update_count(imxg_timer_state *s)
> +{
> + uint64_t clk = qemu_get_clock_ns(vm_clock);
> + s->cnt = ((uint32_t)muldiv64(clk, GPT_FREQ,
> + get_ticks_per_sec())) % TIMER_MAX;
> + return clk;
> +}
> +
> +static void imxg_timer_run(imxg_timer_state *s, uint32_t timeout)
> +{
> + uint64_t clk = imxg_timer_update_count(s);
> + uint32_t diff_cnt;
> + if (s->cnt< timeout) {
> + diff_cnt = (timeout - s->cnt);
> + s->waiting_rov = 0;
> + } else {
> + diff_cnt = (TIMER_MAX - s->cnt);
> + s->waiting_rov = 1;
> + }
> + qemu_mod_timer(s->timer, clk + muldiv64(get_ticks_per_sec(), diff_cnt, GPT_FREQ));
> +}
> +
> +static uint32_t imxg_timer_read(void *opaque, target_phys_addr_t offset)
> +{
> + imxg_timer_state *s = (imxg_timer_state *)opaque;
> +
> + DPRINTF("g-read(offset=%x)\n", offset>> 2);
> + switch (offset>> 2) {
> + case 0: /* CR */
> + return s->cr;
> +
> + case 1: /* prescaler */
> + return s->pr;
> +
> + case 2:
> + return s->sr;
> +
> + case 3:
> + return s->ir;
> +
> + case 4:
> + return s->ocr1;
> +
> + case 9: /* cnt */
> + imxg_timer_update_count(s);
> + return s->cnt;
> + }
> +
> + cpu_abort (cpu_single_env, "imxg_timer_read: Bad offset %x\n",
> + (int)offset>> 2);
> +}
> +
> +static void imxg_timer_write(void *opaque, target_phys_addr_t offset,
> + uint32_t value)
> +{
> + imxg_timer_state *s = (imxg_timer_state *)opaque;
> + DPRINTF("g-write(offset=%x, value = %x)\n", offset>> 2, value);
> +
> + switch (offset>> 2) {
> + case 0: /* CR */
> + if (!(s->cr& GPT_CR_EN)&& (value& GPT_CR_EN)) {
> + imxg_timer_run(s, s->ocr1);
> + };
> + if ((s->cr& GPT_CR_EN)&& !(value& GPT_CR_EN)) {
> + qemu_del_timer(s->timer);
> + };
> + s->cr = value;
> + return;
> + case 1:
> + s->pr = value;
> + return;
> +
> + case 2:
> + if (value& GPT_SR_OF1) {
> + s->sr&= ~GPT_SR_OF1;
> + }
> + if (value& GPT_SR_ROV) {
> + s->sr&= ~GPT_SR_ROV;
> + }
> + imxg_timer_update(s);
> + return;
> +
> + case 3:
> + s->ir = value;
> + imxg_timer_update(s);
> + return;
> +
> + case 4:
> + if (s->cr& GPT_CR_EN) {
> + s->ocr1 = value;
> + imxg_timer_run(s, s->ocr1);
> + }
> + return;
> +
> + default:
> + cpu_abort (cpu_single_env, "imxg_timer_write: Bad offset %x\n",
> + (int)offset>> 2);
> + }
> +}
> +
> +static void imxg_timer_timeout(void *opaque) {
> + imxg_timer_state *s = (imxg_timer_state *)opaque;
> +
> + if (s->waiting_rov) {
> + s->sr |= GPT_SR_ROV;
> + imxg_timer_run(s, s->ocr1);
> + } else {
> + s->sr |= GPT_SR_OF1;
> + imxg_timer_run(s, 0);
> + }
> + imxg_timer_update(s);
> +}
> +
> +static CPUReadMemoryFunc *imxg_timer_readfn[] = {
> + imxg_timer_read,
> + imxg_timer_read,
> + imxg_timer_read
> +};
> +
> +static CPUWriteMemoryFunc *imxg_timer_writefn[] = {
> + imxg_timer_write,
> + imxg_timer_write,
> + imxg_timer_write
> +};
> +
> +void imxg_timer_init(uint32_t base, qemu_irq irq)
> +{
> + int iomemtype;
> + imxg_timer_state *s;
> +
> + s = (imxg_timer_state *)g_malloc0(sizeof(imxg_timer_state));
> + s->base = base;
> + s->cr = 0;
> + s->ir = 0;
> + s->pr = 0;
> + s->ocr1 = 0;
> + s->irq = irq;
> + s->timer = qemu_new_timer_ns(vm_clock, imxg_timer_timeout, s);
> + imxg_timer_update_count(s);
> +
> + iomemtype = cpu_register_io_memory(imxg_timer_readfn,
> + imxg_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
> + cpu_register_physical_memory(base, 0x00001000, iomemtype);
> +}
> +
> +
> +
> +/*
> + * EPIT :Enhanced periodic interrupt timer
> + */
> +
> +#define EPIT_FREQ 1000000
> +#define TIMER_TICK_LENGTH 5000
> +#define IMX31_TICKS_PER_TIMESLICE (72 * TIMER_TICK_LENGTH)
> +#define CR_EN (1<< 0)
> +#define CR_SWR (1<< 16)
> +typedef struct {
> + uint32_t base;
> + ptimer_state *timer;
> + uint32_t cr;
> + uint32_t lr;
> + uint32_t cmp;
> + int int_level;
> + qemu_irq irq;
> +} imxp_timer_state;
> +
> +/* Check all active timers, and schedule the next timer interrupt. */
> +static void imxp_timer_update(imxp_timer_state *s)
> +{
> + /* Update interrupts. */
> + if (s->int_level&& (s->cr& CR_EN)) {
> + qemu_irq_raise(s->irq);
> + } else {
> + qemu_irq_lower(s->irq);
> + }
> +}
> +
> +static uint32_t imxp_timer_read(void *opaque, target_phys_addr_t offset)
> +{
> + imxp_timer_state *s = (imxp_timer_state *)opaque;
> +
> + DPRINTF("p-read(offset=%x)\n", offset);
> + switch (offset>> 2) {
> + case 0: /* CR */
> + return s->cr;
> +
> + case 1: /* SR */
> + return s->int_level;
> +
> + case 2: /* LR - set ticks*/
> + return s->lr;
> +
> + case 3: /* CMP */
> + return s->cmp;
> +
> + case 4: /* CNT */
> + return ptimer_get_count(s->timer);
> + }
> + cpu_abort (cpu_single_env, "imxp_timer_read: Bad offset %x\n",
> + (int)offset>> 2);
> +}
> +
> +static void imxp_timer_write(void *opaque, target_phys_addr_t offset,
> + uint32_t value)
> +{
> + imxp_timer_state *s = (imxp_timer_state *)opaque;
> + DPRINTF("p-write(offset=%x, value = %x)\n", offset>> 2, value);
> +
> + switch (offset>> 2) {
> + case 0: /* CR */
> + s->cr = value;
> + if (s->cr& CR_EN) {
> + ptimer_run(s->timer,0);
> + } else {
> + ptimer_stop(s->timer);
> + }
> + if (s->cr& CR_SWR) {
> + s->cr = 0;
> + s->lr = 0;
> + ptimer_stop(s->timer);
> + }
> + break;
> + case 1: /* SR - ACK*/
> + s->int_level=0;
> + imxp_timer_update(s);
> + break;
> +
> + case 2: /* LR - set ticks*/
> + s->lr = value;
> + ptimer_set_freq(s->timer, EPIT_FREQ);
> + ptimer_set_limit(s->timer, value, 1);
> + break;
> +
> + case 3: /* CMP */
> + s->cmp = value;
> + break;
> +
> +
> + default:
> + cpu_abort (cpu_single_env, "imxp_timer_write: Bad offset %x\n",
> + (int)offset>> 2);
> + }
> +}
> +
> +static void imxp_timer_tick(void *opaque)
> +{
> + imxp_timer_state *s = (imxp_timer_state *)opaque;
> + s->int_level = 1;
> + imxp_timer_update(s);
> +}
> +
> +static CPUReadMemoryFunc *imxp_timer_readfn[] = {
> + imxp_timer_read,
> + imxp_timer_read,
> + imxp_timer_read
> +};
> +
> +static CPUWriteMemoryFunc *imxp_timer_writefn[] = {
> + imxp_timer_write,
> + imxp_timer_write,
> + imxp_timer_write
> +};
> +
> +static const VMStateDescription vmstate_imxp_timer = {
> + .name = "imxp_timer",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(cr, imxp_timer_state),
> + VMSTATE_UINT32(lr, imxp_timer_state),
> + VMSTATE_INT32(int_level, imxp_timer_state),
> + VMSTATE_PTIMER(timer, imxp_timer_state),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +void imxp_timer_init(uint32_t base, qemu_irq irq)
> +{
> + int iomemtype;
> + imxp_timer_state *s;
> + QEMUBH *bh;
> +
> + s = (imxp_timer_state *)g_malloc0(sizeof(imxp_timer_state));
> + s->base = base;
> + s->cr = 0;
> + s->lr = 0;
> + s->irq = irq;
> +
> + bh = qemu_bh_new(imxp_timer_tick, s);
> + s->timer = ptimer_init(bh);
> + vmstate_register(NULL, -1,&vmstate_imxp_timer, s);
> + iomemtype = cpu_register_io_memory(imxp_timer_readfn,
> + imxp_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
> + cpu_register_physical_memory(base, 0x00001000, iomemtype);
> +}
> diff --git a/hw/imx.h b/hw/imx.h
> new file mode 100644
> index 0000000..cf0088f
> --- /dev/null
> +++ b/hw/imx.h
> @@ -0,0 +1,14 @@
> +#ifndef hw_imx_h
> +
> +#include "hw.h"
> +
> +/*
> + * ARM11 IMX processor initial port.
> + *
> + */
> +void imx_serial_init(uint32_t base, qemu_irq irq, CharDriverState *chr);
> +void imxp_timer_init(uint32_t base, qemu_irq irq);
> +void imxg_timer_init(uint32_t base, qemu_irq irq);
> +qemu_irq *imx_int_init(uint32_t base, qemu_irq irq);
> +
> +#endif /* hw_imx_h */
> diff --git a/hw/kzm.c b/hw/kzm.c
> new file mode 100644
> index 0000000..3b9cca2
> --- /dev/null
> +++ b/hw/kzm.c
> @@ -0,0 +1,86 @@
> +/*
> + * KZM Board System emulation.
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.
> + */
> +
> +#include "imx.h"
> +#include "hw.h"
> +#include "arm-misc.h"
> +#include "primecell.h"
> +#include "devices.h"
> +#include "pci.h"
> +#include "net.h"
> +#include "sysemu.h"
> +#include "boards.h"
> +
> +/* Board init. */
> +
> +static struct arm_boot_info kzm_binfo = {
> + .loader_start = 0x0,
> + .board_id = 0x33b,
> +};
> +
> +static void kzm_init(ram_addr_t ram_size,
> + const char *boot_device,
> + const char *kernel_filename, const char *kernel_cmdline,
> + const char *initrd_filename, const char *cpu_model)
> +{
> + CPUState *env;
> + ram_addr_t ram_offset;
> +
> + qemu_irq *pic;
> + qemu_irq cpu_irq;
> +
> + if (!cpu_model) {
> + cpu_model = "arm1136";
> + }
> +
> + env = cpu_init(cpu_model);
> + if (!env) {
> + fprintf(stderr, "Unable to find CPU definition\n");
> + exit(1);
> + }
> + pic = arm_pic_init_cpu(env);
> + cpu_irq = pic[ARM_PIC_CPU_IRQ];
> +
> + ram_offset = qemu_ram_alloc(NULL, "kzm.ram", ram_size);
> + cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM);
> +
> + pic = imx_int_init(0x68000000, cpu_irq);
> +
> + imx_serial_init(0x43f90000, pic[45], serial_hds[0]);
> + imxp_timer_init(0x53f94000, pic[28]);
> + imxp_timer_init(0x53f98000, pic[27]);
> + imxg_timer_init(0x53f90000, pic[29]);
> +
> + /* Memory map for Kzm Emulation Baseboard: */
> +
> + /* 0x43f00000 IO_AREA0 */
> + /* 0x43f90000 UART1 */
> + /* 0x43f94000 UART2 */
> +
> + kzm_binfo.ram_size = ram_size;
> + kzm_binfo.kernel_filename = kernel_filename;
> + kzm_binfo.kernel_cmdline = kernel_cmdline;
> + kzm_binfo.initrd_filename = initrd_filename;
> + kzm_binfo.initrd_filename = initrd_filename;
> + kzm_binfo.nb_cpus = 1;
> + arm_load_kernel(first_cpu,&kzm_binfo);
> +}
> +
> +QEMUMachine kzm_machine = {
> + .name = "kzm",
> + .desc = "ARM KZM Emulation Baseboard (ARM1136)",
> + .init = kzm_init,
> +};
> +
> +static void kzm_machine_init(void)
> +{
> + qemu_register_machine(&kzm_machine);
> +}
> +
> +machine_init(kzm_machine_init);
> diff --git a/hw/kzm.h b/hw/kzm.h
> new file mode 100644
> index 0000000..7fad04e
> --- /dev/null
> +++ b/hw/kzm.h
> @@ -0,0 +1,5 @@
> +void imxp_timer_init(uint32_t base, qemu_irq irq);
> +void imx_serial_init(uint32_t base, qemu_irq irq, CharDriverState *chr);
> +qemu_irq *imx_int_init(uint32_t base, qemu_irq irq);
> +
> +
prev parent reply other threads:[~2011-09-23 14:39 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-23 0:50 [Qemu-devel] [PATCH] Add KZM board support to qemu Peter Chubb
2011-09-23 14:38 ` Anthony Liguori [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E7C9A02.7000906@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=adamc@ok-labs.com \
--cc=hsjang@ok-labs.com \
--cc=peter.chubb@nicta.com.au \
--cc=peter.maydell@linaro.org \
--cc=philipo@ok-labs.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.