From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:46529) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R76uF-0006q7-Fc for qemu-devel@nongnu.org; Fri, 23 Sep 2011 10:39:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1R76u8-00023J-9j for qemu-devel@nongnu.org; Fri, 23 Sep 2011 10:39:11 -0400 Received: from mail-yx0-f173.google.com ([209.85.213.173]:62285) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R76u8-00023C-2v for qemu-devel@nongnu.org; Fri, 23 Sep 2011 10:39:04 -0400 Received: by yxl11 with SMTP id 11so3450727yxl.4 for ; Fri, 23 Sep 2011 07:39:02 -0700 (PDT) Message-ID: <4E7C9A02.7000906@codemonkey.ws> Date: Fri, 23 Sep 2011 09:38:58 -0500 From: Anthony Liguori MIME-Version: 1.0 References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH] Add KZM board support to qemu List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Peter Chubb Cc: Peter Maydell , hsjang@ok-labs.com, qemu-devel@nongnu.org, philipo@ok-labs.com, adamc@ok-labs.com 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 > Signed-Off-By: Hans Jang > Signed-off-by: Adam Clench 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); > + > +