* [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support
@ 2011-11-30 3:36 Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series Peter Chubb
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Peter Chubb @ 2011-11-30 3:36 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel, Andreas Färber
Changes since last patchset:
* All files now under GPL version 2 or later (I've talked with
OK-Labs and they've agreed).
* `DPRINTF' like macro for printing out guest kernel and qemu
implementation errors
* Fixed bugs in avic implementation, as found by PMM
* Use a static initialiser and sysbus_register_withprop() instead of
calls to sysbus_register() adn vmstate_register()
* Fixed bugs in imx_timer.c as noted by PMM and Andreas
--
Dr Peter Chubb http://www.gelato.unsw.edu.au peterc AT gelato.unsw.edu.au
http://www.ertos.nicta.com.au ERTOS within National ICT Australia
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series.
2011-11-30 3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
@ 2011-11-30 3:36 ` Peter Chubb
2011-12-01 16:55 ` Peter Maydell
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run Peter Chubb
` (3 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Peter Chubb @ 2011-11-30 3:36 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
[-- Attachment #1: imx-serial.patch --]
[-- Type: text/plain, Size: 9834 bytes --]
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: Adam Clench <adamc@ok-labs.com>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
---
Makefile.target | 1
hw/imx_serial.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 321 insertions(+)
create mode 100644 hw/imx_serial.c
Index: qemu-working/hw/imx_serial.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu-working/hw/imx_serial.c 2011-11-30 13:38:24.434778115 +1100
@@ -0,0 +1,320 @@
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Originally Written by Hans Jiang
+ * Copyright (c) 2011 NICTA Pty Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * This is a `bare-bones' implementation of the IMX series serial ports.
+ * TODO:
+ * -- implement FIFOs. The real hardware has 32 word transmit
+ * and receive FIFOs; we currently use a 1-char buffer
+ * -- implement DMA
+ * -- implement BAUD-rate and modem lines, for when the backend
+ * is a real serial device.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "qemu-char.h"
+
+//#define DEBUG_SERIAL 1
+
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, args...) \
+do { printf("imx_serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
+#else
+# define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ int32_t readbuff;
+
+ uint32_t usr1;
+ uint32_t usr2;
+ uint32_t ucr1;
+ uint32_t uts1;
+
+ uint32_t ubrm;
+ uint32_t ubrc;
+
+ qemu_irq irq;
+ CharDriverState *chr;
+} imx_state;
+
+static const VMStateDescription vmstate_imx_serial = {
+ .name = "imx-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(readbuff, imx_state),
+ VMSTATE_UINT32(usr1, imx_state),
+ VMSTATE_UINT32(usr2, imx_state),
+ VMSTATE_UINT32(ucr1, imx_state),
+ VMSTATE_UINT32(uts1, imx_state),
+ VMSTATE_UINT32(ubrm, imx_state),
+ VMSTATE_UINT32(ubrc, imx_state),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+
+#define URXD_CHARRDY (1<<15) /* character read is valid */
+
+#define USR1_TRDY (1<<13) /* Xmitter ready */
+#define USR1_RRDY (1<<9) /* receiver ready */
+
+#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
+#define USR2_TXDC (1<<3) /* Transmission complete */
+#define USR2_RDR (1<<0) /* Receive data ready */
+
+#define UCR1_TRDYEN (1<<13)
+#define UCR1_RRDYEN (1<<9)
+#define UCR1_TXMPTYEN (1<<6)
+#define UCR1_UARTEN (1<<0)
+
+#define UTS1_TXEMPTY (1<<6)
+#define UTS1_RXEMPTY (1<<5)
+#define UTS1_TXFULL (1<<4)
+#define UTS1_RXFULL (1<<3)
+
+static void imx_update(imx_state *s)
+{
+ uint32_t flags;
+
+ flags = ((s->usr1 & s->ucr1)) & (USR1_TRDY|USR1_RRDY);
+ if (!(s->ucr1 & UCR1_TXMPTYEN)) {
+ flags &= ~USR1_TRDY;
+ }
+
+ if (flags) {
+ DPRINTF("imx_serial: raising interrupt\n");
+ }
+
+ qemu_set_irq(s->irq, !!flags);
+}
+
+static void imx_serial_reset(DeviceState *dev)
+{
+ imx_state *s = container_of(dev, imx_state, busdev.qdev);
+
+ s->usr1 = USR1_TRDY;
+ s->usr2 = USR2_TXFE | USR2_TXDC;
+ s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
+ s->ubrm = 0;
+ s->ubrc = 0;
+ s->readbuff = 0;
+
+ imx_update(s);
+}
+
+static uint64_t imx_serial_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ 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;
+ if (!(s->uts1 & UTS1_RXEMPTY)) {
+ /* Character is valid */
+ c |= URXD_CHARRDY;
+ s->usr1 &= ~USR1_RRDY;
+ s->usr2 &= ~USR2_RDR;
+ s->uts1 |= UTS1_RXEMPTY;
+ imx_update(s);
+ qemu_chr_accept_input(s->chr);
+ }
+ return c;
+
+ case 0x20: /* UCR1 */
+ return s->ucr1;
+
+ case 0x21: /* UCR2 */
+ return 1; /* reset complete */
+
+ case 0x25: /* USR1 */
+ return s->usr1;
+
+ case 0x26: /* USR2 */
+ return s->usr2;
+
+ case 0x2A: /* BRM Modulator */
+ return s->ubrm;
+
+ case 0x2B: /* Baud Rate Count */
+ return s->ubrc;
+
+ case 0x2d: /* UTS1 */
+ return s->uts1;
+
+ case 0x22: /* UCR3 */
+ case 0x23: /* UCR4 */
+ case 0x24: /* UFCR */
+ case 0x29: /* BRM Incremental */
+ return 0x0; /* TODO */
+
+ default:
+ IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
+ return 0;
+ }
+}
+
+static void imx_serial_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ imx_state *s = (imx_state *)opaque;
+ unsigned char ch;
+
+ DPRINTF("write(offset=%x, value = %x)\n", offset >> 2, (unsigned int)value);
+ switch (offset >> 2) {
+ case 0x10: /* UTXD */
+ ch = value;
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ s->usr1 &= ~USR1_TRDY;
+ imx_update(s);
+ s->usr1 |= USR1_TRDY;
+ imx_update(s);
+ break;
+
+ case 0x20: /* UCR1 */
+ s->ucr1 = value;
+ DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
+ imx_update(s);
+ break;
+
+ case 0x21: /* UCR2 */
+ if (!(value & 1)) {
+ imx_serial_reset(&s->busdev.qdev);
+ }
+ break;
+
+ case 0x26: /* USR2 */
+ /*
+ * Writing 1 to some bits clears them; all other
+ * values are ignored
+ */
+ value &= (1<<15) | (1<<13) | (1<<12) | (1<<11) | (1<<10)|
+ (1<<8) | (1<<7) | (1<<6) | (1<<4) | (1<<2) | (1<<1);
+ s->usr2 &= ~value;
+ break;
+
+ /* Linux expects to see what it writes here. */
+ /* We don't currently alter the baud rate */
+ case 0x29: /* UBIR */
+ s->ubrc = value;
+ break;
+
+ case 0x2a: /* UBRM */
+ s->ubrm = value;
+ break;
+
+ case 0x2d: /* UTS1 */
+ case 0x22: /* UCR3 */
+ case 0x23: /* UCR4 */
+ case 0x24: /* UFCR */
+ case 0x25: /* USR1 */
+ case 0x2c: /* BIPR1 */
+ /* TODO */
+ break;
+
+ default:
+ IPRINTF("imx_serial_write: Bad offset 0x%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 const struct MemoryRegionOps imx_serial_ops = {
+ .read = imx_serial_read,
+ .write = imx_serial_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx_serial_init(SysBusDevice *dev)
+{
+ imx_state *s = FROM_SYSBUS(imx_state, dev);
+
+ memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
+ sysbus_init_mmio_region(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+ s->chr = qdev_init_chardev(&dev->qdev);
+ /*
+ * enable the uart on boot, so messages from the linux decompresser
+ * are visible. On real hardware this is done by the boot rom
+ * before anything else is loaded.
+ */
+ s->ucr1 = UCR1_UARTEN;
+
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+ imx_event, s);
+ }
+ return 0;
+}
+
+static SysBusDeviceInfo imx_serial_info = {
+ .qdev.name = "imx_serial",
+ .qdev.desc = "i.MX series UART",
+ .qdev.size = sizeof (imx_state),
+ .qdev.vmsd = &vmstate_imx_serial,
+ .qdev.reset = imx_serial_reset,
+ .init = imx_serial_init,
+};
+
+static void imx_serial_register_devices(void)
+{
+ sysbus_register_withprop(&imx_serial_info);
+}
+
+device_init(imx_serial_register_devices)
Index: qemu-working/Makefile.target
===================================================================
--- qemu-working.orig/Makefile.target 2011-11-30 13:38:19.886754597 +1100
+++ qemu-working/Makefile.target 2011-11-30 13:38:24.434778115 +1100
@@ -361,20 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += strongarm.o
obj-arm-y += collie.o
obj-arm-y += pl041.o lm4549.o
+obj-arm-y += imx_serial.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
obj-sh4-y += ide/mmio.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run.
2011-11-30 3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series Peter Chubb
@ 2011-11-30 3:36 ` Peter Chubb
2011-12-01 17:11 ` Peter Maydell
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x Peter Chubb
` (2 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Peter Chubb @ 2011-11-30 3:36 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
[-- Attachment #1: imx-timer.patch --]
[-- Type: text/plain, Size: 13981 bytes --]
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: Adam Clench <adamc@ok-labs.com>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
---
Makefile.target | 2
hw/imx_timer.c | 460 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 461 insertions(+), 1 deletion(-)
create mode 100644 hw/imx_timer.c
Index: qemu-working/hw/imx_timer.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu-working/hw/imx_timer.c 2011-11-30 13:38:25.818785258 +1100
@@ -0,0 +1,460 @@
+/*
+ * IMX31 Timer
+ *
+ * Copyright (c) 2008 OKL
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally Written by Hans Jiang
+ * Updated by Peter Chubb
+ *
+ * This code is licenced under GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysbus.h"
+
+//#define DEBUG_TIMER 1
+
+#ifdef DEBUG_TIMER
+# define DPRINTF(fmt, args...) \
+ do { printf("imx_timer: " fmt , ##args); } while (0)
+#else
+# define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+#else
+# define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * GPT : General purpose timer
+ */
+
+#define TIMER_MAX 0xFFFFFFFFUL
+#define GPT_FREQ 50000000 /* Hz == 50 MHz */
+
+/* Control register. Not all of these bits have any effect (yet) */
+#define GPT_CR_EN (1 << 0) /* GPT Enable */
+#define GPT_CR_ENMODE (1 << 1) /* GPT Enable Mode */
+#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */
+#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */
+#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */
+#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */
+#define GPT_CR_CLKSRC (7 << 6) /* Clock source select (3 bits) */
+#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */
+#define GPT_CR_SWR (1 << 15)
+#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */
+#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */
+#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
+#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
+#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
+#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */
+#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */
+#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */
+
+#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 {
+ SysBusDevice busdev;
+ QEMUTimer *timer;
+ MemoryRegion iomem;
+ 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;
+
+static const VMStateDescription vmstate_imxg_timer = {
+ .name = "imxg-timer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(cr, imxg_timer_state),
+ VMSTATE_UINT32(sr, imxg_timer_state),
+ VMSTATE_UINT32(ir, imxg_timer_state),
+ VMSTATE_UINT32(cnt, imxg_timer_state),
+ VMSTATE_UINT32(ocr1, imxg_timer_state),
+ VMSTATE_TIMER(timer, imxg_timer_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+/* Check all active timers, and schedule the next timer interrupt. */
+static void imxg_timer_update(imxg_timer_state *s)
+{
+ uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
+
+ if ((s->cr & GPT_CR_EN) && flags) {
+ 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/1000000,
+ 1000)) % 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 + diff_cnt * 1000 / (GPT_FREQ/1000000));
+}
+
+static uint64_t imxg_timer_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ 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;
+ }
+
+ IPRINTF("imxg_timer_read: Bad offset %x\n",
+ (int)offset >> 2);
+ return 0;
+}
+
+static void imxg_timer_reset(DeviceState *dev)
+{
+ imxg_timer_state *s = container_of(dev, imxg_timer_state, busdev.qdev);
+
+ s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
+ s->sr = 0;
+ s->pr = 0;
+ s->ir = 0;
+ s->cnt = 0;
+ s->ocr1 = 0;
+ imxg_timer_update_count(s);
+ imxg_timer_update(s);
+}
+
+static void imxg_timer_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ imxg_timer_state *s = (imxg_timer_state *)opaque;
+ DPRINTF("g-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
+ (unsigned int)value);
+
+ switch (offset >> 2) {
+ case 0: /* CR */
+ if (value & GPT_CR_SWR) { /* force reset */
+ value &= ~GPT_CR_SWR;
+ imxg_timer_reset(&s->busdev.qdev);
+ }
+ if (!(s->cr & GPT_CR_EN) && (value & GPT_CR_EN)) {
+ if (value & GPT_CR_ENMODE) {
+ s->cnt = 0;
+ }
+ imxg_timer_run(s, s->ocr1);
+ } else 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:
+ s->ocr1 = value;
+ if (s->cr & GPT_CR_EN) {
+ imxg_timer_run(s, s->ocr1);
+ }
+ return;
+
+ default:
+ IPRINTF("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;
+
+ DPRINTF("imxg_timer_timeout\n");
+ 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 const MemoryRegionOps imxg_timer_ops = {
+ .read = imxg_timer_read,
+ .write = imxg_timer_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static int imxg_timer_init(SysBusDevice *dev)
+{
+ imxg_timer_state *s = FROM_SYSBUS(imxg_timer_state, dev);
+
+ sysbus_init_irq(dev, &s->irq);
+ memory_region_init_io(&s->iomem, &imxg_timer_ops,
+ s, "imxg-timer",
+ 0x00001000);
+ sysbus_init_mmio_region(dev, &s->iomem);
+
+ s->timer = qemu_new_timer_ns(vm_clock, imxg_timer_timeout, s);
+ imxg_timer_reset(&dev->qdev);
+ return 0;
+}
+
+
+
+/*
+ * 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 {
+ SysBusDevice busdev;
+ ptimer_state *timer;
+ MemoryRegion iomem;
+ 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 void imxp_timer_reset(DeviceState *dev)
+{
+ imxp_timer_state *s = container_of(dev, imxp_timer_state, busdev.qdev);
+
+ s->cr = 0;
+ s->lr = 0;
+ ptimer_stop(s->timer);
+}
+
+static uint64_t imxp_timer_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ 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);
+ }
+ IPRINTF("imxp_timer_read: Bad offset %x\n",
+ (int)offset >> 2);
+ return 0;
+}
+
+static void imxp_timer_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ imxp_timer_state *s = (imxp_timer_state *)opaque;
+ DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
+ (unsigned int)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) {
+ imxp_timer_reset(&s->busdev.qdev);
+ }
+ 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:
+ IPRINTF("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 const MemoryRegionOps imxp_timer_ops = {
+ .read = imxp_timer_read,
+ .write = imxp_timer_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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_UINT32(cmp, imxp_timer_state),
+ VMSTATE_INT32(int_level, imxp_timer_state),
+ VMSTATE_PTIMER(timer, imxp_timer_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int imxp_timer_init(SysBusDevice *dev)
+{
+ imxp_timer_state *s = FROM_SYSBUS(imxp_timer_state, dev);
+ QEMUBH *bh;
+
+ DPRINTF("imxp_timer_init\n");
+
+ sysbus_init_irq(dev, &s->irq);
+ memory_region_init_io(&s->iomem, &imxp_timer_ops,
+ s, "imxp-timer",
+ 0x00001000);
+ sysbus_init_mmio_region(dev, &s->iomem);
+
+ bh = qemu_bh_new(imxp_timer_tick, s);
+ s->timer = ptimer_init(bh);
+ imxp_timer_reset(&s->busdev.qdev);
+
+ return 0;
+}
+
+static SysBusDeviceInfo imx_timerp_info = {
+ .qdev.name = "imx_timerp",
+ .qdev.desc = "i.MX Periodic Timer",
+ .qdev.size = sizeof (imxp_timer_state),
+ .qdev.vmsd = &vmstate_imxp_timer,
+ .qdev.reset = imxp_timer_reset,
+ .init = imxp_timer_init,
+
+};
+
+static SysBusDeviceInfo imx_timerg_info = {
+ .qdev.name = "imx_timerg",
+ .qdev.desc = "i.MX General Timer",
+ .qdev.size = sizeof (imxg_timer_state),
+ .qdev.vmsd = &vmstate_imxg_timer,
+ .qdev.reset = imxg_timer_reset,
+ .init = imxg_timer_init,
+};
+
+static void imx_timer_register_devices(void)
+{
+ sysbus_register_withprop(&imx_timerp_info);
+ sysbus_register_withprop(&imx_timerg_info);
+}
+
+device_init(imx_timer_register_devices)
Index: qemu-working/Makefile.target
===================================================================
--- qemu-working.orig/Makefile.target 2011-11-30 13:38:24.786779925 +1100
+++ qemu-working/Makefile.target 2011-11-30 13:38:25.818785258 +1100
@@ -361,21 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += strongarm.o
obj-arm-y += collie.o
obj-arm-y += pl041.o lm4549.o
-obj-arm-y += imx_serial.o
+obj-arm-y += imx_serial.o imx_timer.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
obj-sh4-y += ide/mmio.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x
2011-11-30 3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run Peter Chubb
@ 2011-11-30 3:36 ` Peter Chubb
2011-12-01 17:26 ` Peter Maydell
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 4/4] Board support for Kyoto Micros KZM-ARM11-01, an evaluation board built around the FreeScale i.MX31 Peter Chubb
2011-11-30 6:15 ` [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Stefan Weil
4 siblings, 1 reply; 14+ messages in thread
From: Peter Chubb @ 2011-11-30 3:36 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
[-- Attachment #1: imx-avic.patch --]
[-- Type: text/plain, Size: 13149 bytes --]
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: Adam Clench <adamc@ok-labs.com>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
---
Makefile.target | 2
hw/imx_avic.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 379 insertions(+), 1 deletion(-)
create mode 100644 hw/imx_avic.c
Index: qemu-working/hw/imx_avic.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu-working/hw/imx_avic.c 2011-11-30 13:38:27.070791665 +1100
@@ -0,0 +1,378 @@
+/*
+ * IMX31 Vectored Interrupt Controller
+ *
+ * Note this is NOT the PL192 provided by ARM, but
+ * a custom implementation by FreeScale.
+ *
+ * Copyright (c) 2008 OKL
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally Written by Hans Jiang
+ *
+ * This code is licenced under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ * TODO: implement vectors and priorities.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "host-utils.h"
+
+#define DEBUG_INT 1
+#undef DEBUG_INT /* comment out for debugging */
+
+#ifdef DEBUG_INT
+#define DPRINTF(fmt, args...) \
+do { printf("imx_avic: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
+#else
+# define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define IMX_INT_NUM_IRQS 64
+
+/* Interrupt Control Bits */
+#define ABFLAG (1<<25)
+#define ABFEN (1<<24)
+#define NIDIS (1<<22) /* Normal Interrupt disable */
+#define FIDIS (1<<21) /* Fast interrupt disable */
+#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
+#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
+#define NM (1<<18) /* Normal interrupt mode */
+
+
+#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
+#define PRIO_WORDS (IMX_INT_NUM_IRQS/PRIO_PER_WORD)
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ uint64_t pending;
+ uint64_t enabled;
+ uint64_t is_fiq;
+ uint32_t intcntl;
+ uint32_t intmask;
+ qemu_irq irq;
+ qemu_irq fiq;
+ uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
+} imx_int_state;
+
+static const VMStateDescription vmstate_imx_avic = {
+ .name = "imx-avic",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(pending, imx_int_state),
+ VMSTATE_UINT64(enabled, imx_int_state),
+ VMSTATE_UINT64(is_fiq, imx_int_state),
+ VMSTATE_UINT32(intcntl, imx_int_state),
+ VMSTATE_UINT32(intmask, imx_int_state),
+ VMSTATE_UINT32_ARRAY(prio, imx_int_state, PRIO_WORDS),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+
+
+static inline int imx_int_prio(imx_int_state *s, int irq)
+{
+ uint32_t word = irq / PRIO_PER_WORD;
+ uint32_t part = 4 * (irq % PRIO_PER_WORD);
+ return 0xf & (s->prio[word] >> part);
+}
+
+static inline void imx_int_set_prio(imx_int_state *s, int irq, int prio)
+{
+ uint32_t word = irq / PRIO_PER_WORD;
+ uint32_t part = 4 * (irq % PRIO_PER_WORD);
+ uint32_t mask = ~(0xf << part);
+ s->prio[word] &= mask;
+ s->prio[word] |= prio << part;
+}
+
+/* Update interrupts. */
+static void imx_int_update(imx_int_state *s)
+{
+ int i;
+ uint64_t new = s->pending;
+ uint64_t flags;
+
+ flags = new & s->enabled & s->is_fiq;
+ qemu_set_irq(s->fiq, !!flags);
+
+ flags = new & s->enabled & ~s->is_fiq;
+ if (!flags || (s->intmask == 0x1f)) {
+ qemu_set_irq(s->irq, !!flags);
+ return;
+ }
+
+ /*
+ * Take interrupt if prio lower than the value of intmask
+ * (should really take highest priority interrupt here,
+ * but that would involve processing interrupt sources
+ * in priority order)
+ */
+ for (i = 0; i < IMX_INT_NUM_IRQS; i++) {
+ if (flags & (1UL << i)) {
+ if (imx_int_prio(s, i) > s->intmask) {
+ qemu_set_irq(s->irq, 1);
+ return;
+ }
+ }
+ }
+ qemu_set_irq(s->irq, 0);
+}
+
+static void imx_int_set_irq(void *opaque, int irq, int level)
+{
+ imx_int_state *s = (imx_int_state *)opaque;
+
+ if (level) {
+ s->pending |= (1ULL << irq);
+ } else {
+ s->pending &= ~(1ULL << irq);
+ }
+
+ imx_int_update(s);
+}
+
+
+static uint64_t imx_int_read(void *opaque,
+ target_phys_addr_t offset, unsigned size)
+{
+ imx_int_state *s = (imx_int_state *)opaque;
+
+
+ DPRINTF("read(offset = 0x%x)\n", offset >> 2);
+ switch (offset >> 2) {
+ case 0: /* INTCNTL */
+ return s->intcntl;
+
+ case 1: /* Normal Interrupt Mask Register, NIMASK */
+ return s->intmask;
+
+ case 2: /* Interrupt Enable Number Register, INTENNUM */
+ case 3: /* Interrupt Disable Number Register, INTDISNUM */
+ return 0;
+
+ case 4: /* Interrupt Enabled Number Register High */
+ return s->enabled >> 32;
+
+ case 5: /* Interrupt Enabled Number Register Low */
+ return s->enabled & 0xffffffffULL;
+
+ case 6: /* Interrupt Type Register High */
+ return s->is_fiq >> 32;
+
+ case 7: /* Interrupt Type Register Low */
+ return s->is_fiq & 0xffffffffULL;
+
+ case 8: /* Normal Interrupt Priority Register 7 */
+ case 9: /* Normal Interrupt Priority Register 6 */
+ case 10:/* Normal Interrupt Priority Register 5 */
+ case 11:/* Normal Interrupt Priority Register 4 */
+ case 12:/* Normal Interrupt Priority Register 3 */
+ case 13:/* Normal Interrupt Priority Register 2 */
+ case 14:/* Normal Interrupt Priority Register 1 */
+ case 15:/* Normal Interrupt Priority Register 0 */
+ return s->prio[15-(offset>>2)];
+
+ case 16: /* Normal interrupt vector and status register */
+ {
+ /*
+ * Note: this is supposed to return highest priority
+ * outstanding interrupt
+ */
+ uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
+ int i = ctz64(flags);
+ if (i < 64) {
+ imx_int_set_irq(opaque, i, 0);
+ return i << 16 | imx_int_prio(s, i);
+ }
+ return 0xffffffffULL;
+ }
+ case 17:/* Fast Interrupt vector and status register */
+ {
+ uint64_t flags = s->pending & s->enabled & s->is_fiq;
+ int i = ctz64(flags);
+ if (i < 64) {
+ imx_int_set_irq(opaque, i, 0);
+ return i;
+ }
+ return 0xffffffffULL;
+ }
+ case 18:/* Interrupt source register high */
+ return s->pending >> 32;
+
+ case 19:/* Interrupt source register low */
+ return s->pending & 0xffffffffULL;
+
+ case 20:/* Interrupt Force Register high */
+ case 21:/* Interrupt Force Register low */
+ return 0;
+
+ case 22:/* Normal Interrupt Pending Register High */
+ return (s->pending & s->enabled & ~s->is_fiq) >> 32;
+
+ case 23:/* Normal Interrupt Pending Register Low */
+ return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
+
+ case 24: /* Fast Interrupt Pending Register High */
+ return (s->pending & s->enabled & s->is_fiq) >> 32;
+
+ case 25: /* Fast Interrupt Pending Register Low */
+ return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
+
+ case 0x40: /* AVIC vector 0, use for WFI WAR */
+ return 0x4;
+
+ default:
+ IPRINTF("imx_int_read: Bad offset 0x%x\n", (int)offset);
+ return 0;
+ }
+}
+
+static void imx_int_write(void *opaque, target_phys_addr_t offset,
+ uint64_t val, unsigned size)
+{
+ imx_int_state *s = (imx_int_state *)opaque;
+
+ /* Vector Registers not yet supported */
+ if (offset >= 0x100 && offset <= 0x2fc) {
+ DPRINTF("imx_int_write to vector register %d\n",
+ (offset - 0x100) >> 2);
+ return;
+ }
+
+ DPRINTF("imx_int_write(0x%x) = %x\n",
+ (unsigned int)offset>>2, (unsigned int)val);
+ switch (offset >> 2) {
+ case 0: /* Interrupt Control Register, INTCNTL */
+ s->intcntl = val & (ABFLAG | ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
+ break;
+
+ case 1: /* Normal Interrupt Mask Register, NIMASK */
+ s->intmask = val & 0x1f;
+ break;
+
+ case 2: /* Interrupt Enable Number Register, INTENNUM */
+ DPRINTF("enable(%d)\n", (int)val);
+ val &= 0x3f;
+ s->enabled |= (1ULL << val);
+ break;
+
+ case 3: /* Interrupt Disable Number Register, INTDISNUM */
+ DPRINTF("disable(%d)\n", (int)val);
+ val &= 0x3f;
+ s->enabled &= ~(1ULL << val);
+ break;
+
+ case 4: /* Interrupt Enable Number Register High */
+ s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
+ break;
+
+ case 5: /* Interrupt Enable Number Register Low */
+ s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
+ break;
+
+ case 6: /* Interrupt Type Register High */
+ s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
+ break;
+
+ case 7: /* Interrupt Type Register Low */
+ s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
+ break;
+
+ case 8: /* Normal Interrupt Priority Register 7 */
+ case 9: /* Normal Interrupt Priority Register 6 */
+ case 10:/* Normal Interrupt Priority Register 5 */
+ case 11:/* Normal Interrupt Priority Register 4 */
+ case 12:/* Normal Interrupt Priority Register 3 */
+ case 13:/* Normal Interrupt Priority Register 2 */
+ case 14:/* Normal Interrupt Priority Register 1 */
+ case 15:/* Normal Interrupt Priority Register 0 */
+ s->prio[15-(offset>>2)] = val;
+ break;
+
+ /* Read-only registers, writes ignored */
+ case 16:/* Normal Interrupt Vector and Status register */
+ case 17:/* Fast Interrupt vector and status register */
+ case 18:/* Interrupt source register high */
+ case 19:/* Interrupt source register low */
+ return;
+
+ case 20:/* Interrupt Force Register high */
+ s->pending = (s->pending & 0xffffffffULL) | (val << 32);
+ break;
+
+ case 21:/* Interrupt Force Register low */
+ s->pending = (s->pending & 0xffffffff00000000ULL) | val;
+ break;
+
+ case 22:/* Normal Interrupt Pending Register High */
+ case 23:/* Normal Interrupt Pending Register Low */
+ case 24: /* Fast Interrupt Pending Register High */
+ case 25: /* Fast Interrupt Pending Register Low */
+ return;
+
+ default:
+ IPRINTF("imx_int_write: Bad offset %x\n", (int)offset);
+ }
+ imx_int_update(s);
+}
+
+static const MemoryRegionOps imx_int_ops = {
+ .read = imx_int_read,
+ .write = imx_int_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_int_reset(DeviceState *dev)
+{
+ imx_int_state *s = container_of(dev, imx_int_state, busdev.qdev);
+ s->intmask = 0x1f;
+ s->enabled = 0;
+}
+
+static int imx_int_init(SysBusDevice *dev)
+{
+ imx_int_state *s = FROM_SYSBUS(imx_int_state, dev);;
+
+ memory_region_init_io(&s->iomem, &imx_int_ops, s, "imx_int", 0x1000);
+ sysbus_init_mmio_region(dev, &s->iomem);
+
+ qdev_init_gpio_in(&dev->qdev, imx_int_set_irq, IMX_INT_NUM_IRQS);
+ sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(dev, &s->fiq);
+
+ return 0;
+}
+
+static SysBusDeviceInfo imx_int_info = {
+ .qdev.name = "imx_int",
+ .qdev.desc = "i.MX Advanced Vector Interrupt Controller",
+ .qdev.size = sizeof (imx_int_state),
+ .qdev.reset = imx_int_reset,
+ .qdev.vmsd = &vmstate_imx_avic,
+ .init = imx_int_init,
+};
+
+static void imx_int_register_devices(void)
+{
+ sysbus_register_withprop(&imx_int_info);
+}
+
+device_init(imx_int_register_devices)
+
Index: qemu-working/Makefile.target
===================================================================
--- qemu-working.orig/Makefile.target 2011-11-30 13:38:26.170787074 +1100
+++ qemu-working/Makefile.target 2011-11-30 13:38:27.070791665 +1100
@@ -361,21 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += strongarm.o
obj-arm-y += collie.o
obj-arm-y += pl041.o lm4549.o
-obj-arm-y += imx_serial.o imx_timer.o
+obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
obj-sh4-y += ide/mmio.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH V3 4/4] Board support for Kyoto Micros KZM-ARM11-01, an evaluation board built around the FreeScale i.MX31.
2011-11-30 3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
` (2 preceding siblings ...)
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x Peter Chubb
@ 2011-11-30 3:36 ` Peter Chubb
2011-11-30 6:15 ` [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Stefan Weil
4 siblings, 0 replies; 14+ messages in thread
From: Peter Chubb @ 2011-11-30 3:36 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
[-- Attachment #1: kzm.patch --]
[-- Type: text/plain, Size: 7398 bytes --]
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: Adam Clench <adamc@ok-labs.com>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
---
Makefile.target | 1
hw/kzm.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 156 insertions(+)
create mode 100644 hw/kzm.c
Index: qemu-working/hw/kzm.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu-working/hw/kzm.c 2011-11-30 13:38:28.210797633 +1100
@@ -0,0 +1,155 @@
+/*
+ * KZM Board System emulation.
+ *
+ * Copyright (c) 2008 OKL and 2011 NICTA
+ * Written by Hans
+ * Updated by Peter Chubb.
+ *
+ * This code is licenced under the GPL, version 2 or later.
+ *
+ * It (partially) emulates a Kyoto Microcomputer
+ * KZM-ARM11-01 evaluation board, with a FreeScale
+ * I.MX31 SoC
+ */
+
+#include "sysbus.h"
+#include "exec-memory.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"
+#include "pc.h" /* for the FPGA UART that emulates a 16550 */
+
+ /* Memory map for Kzm Emulation Baseboard:
+ * 0x00000000-0x00003fff 16k secure ROM IGNORED
+ * 0x00004000-0x00407fff Reserved IGNORED
+ * 0x00404000-0x00407fff ROM IGNORED
+ * 0x00408000-0x0fffffff Reserved IGNORED
+ * 0x10000000-0x1fffBfff RAM aliasing IGNORED
+ * 0x1fffc000-0x1fffffff RAM EMULATED
+ * 0x20000000-0x2fffffff Reserved IGNORED
+ * 0x30000000-0x7fffffff I.MX31 Internal Register Space
+ * 0x43f00000 IO_AREA0
+ * 0x43f90000 UART1 EMULATED
+ * 0x43f94000 UART2 EMULATED
+ * 0x68000000 PIC EMULATED
+ * 0x53f94000 PIT 1 EMULATED
+ * 0x53f98000 PIT 2 EMULATED
+ * 0x53f90000 GPT EMULATED
+ * 0x80000000-0x87ffffff RAM EMULATED
+ * 0x88000000-0x8fffffff RAM Aliasing EMULATED
+ * 0xa0000000-0xafffffff NAND Flash IGNORED
+ * 0xb0000000-0xb3ffffff Unavailable IGNORED
+ * 0xb4000000-0xb4000fff 8-bit free space IGNORED
+ * 0xb4001000-0xb400100f Board control IGNORED
+ * 0xb4001003 DIP switch
+ * 0xb4001010-0xb400101f 7-segment LED IGNORED
+ * 0xb4001020-0xb400102f LED IGNORED
+ * 0xb4001030-0xb400103f LED IGNORED
+ * 0xb4001040-0xb400104f FPGA, UART EMULATED
+ * 0xb4001050-0xb400105f FPGA, UART EMULATED
+ * 0xb4001060-0xb40fffff FPGA IGNORED
+ * 0xb6000000-0xb61fffff LAN controller EMULATED
+ * 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
+ * 0xb6300000-0xb7ffffff Free IGNORED
+ * 0xb8000000-0xb8004fff Memory control registers IGNORED
+ * 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED
+ * 0xc4000000-0xffffffff Reserved IGNORED
+ */
+
+#define KZM_RAMADDRESS (0x80000000)
+#define KZM_FPGA (0xb4001040)
+
+static struct arm_boot_info kzm_binfo = {
+ .loader_start = KZM_RAMADDRESS,
+ .board_id = 1722,
+};
+
+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;
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
+ MemoryRegion *sram = g_new(MemoryRegion, 1);
+ MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
+ qemu_irq *cpu_pic;
+ DeviceState *dev;
+
+ if (!cpu_model) {
+ cpu_model = "arm1136";
+ }
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+
+ /* On a real system, the first 16k is a `secure boot rom' */
+
+ memory_region_init_ram(ram, NULL, "kzm.ram", ram_size);
+ memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
+
+ memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
+ memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
+
+ memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000);
+ memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
+
+
+ cpu_pic = arm_pic_init_cpu(env);
+ dev = sysbus_create_varargs("imx_int", 0x68000000,
+ cpu_pic[ARM_PIC_CPU_IRQ],
+ cpu_pic[ARM_PIC_CPU_FIQ], NULL);
+
+
+ sysbus_create_simple("imx_serial", 0x43f90000, qdev_get_gpio_in(dev, 45));
+ sysbus_create_simple("imx_serial", 0x43f94000, qdev_get_gpio_in(dev, 32));
+ sysbus_create_simple("imx_timerp", 0x53f94000, qdev_get_gpio_in(dev, 28));
+ sysbus_create_simple("imx_timerp", 0x53f98000, qdev_get_gpio_in(dev, 27));
+ sysbus_create_simple("imx_timerg", 0x53f90000, qdev_get_gpio_in(dev, 29));
+
+ if (nd_table[0].vlan) {
+ lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 51));
+ }
+
+ if (serial_hds[3]) {
+ serial_mm_init(address_space_mem, KZM_FPGA, 0,
+ qdev_get_gpio_in(dev, 52),
+ 14745600, serial_hds[3],
+ DEVICE_NATIVE_ENDIAN);
+ }
+ if (serial_hds[2]) { /* touchscreen */
+ serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0,
+ qdev_get_gpio_in(dev, 52),
+ 14745600, serial_hds[2],
+ DEVICE_NATIVE_ENDIAN);
+ }
+
+ 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.nb_cpus = 1;
+ arm_load_kernel(first_cpu, &kzm_binfo);
+}
+
+static 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);
Index: qemu-working/Makefile.target
===================================================================
--- qemu-working.orig/Makefile.target 2011-11-30 13:38:27.426793563 +1100
+++ qemu-working/Makefile.target 2011-11-30 13:38:28.210797633 +1100
@@ -362,20 +362,21 @@ obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += strongarm.o
obj-arm-y += collie.o
obj-arm-y += pl041.o lm4549.o
obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
+obj-arm-y += kzm.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
obj-sh4-y += ide/mmio.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support
2011-11-30 3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
` (3 preceding siblings ...)
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 4/4] Board support for Kyoto Micros KZM-ARM11-01, an evaluation board built around the FreeScale i.MX31 Peter Chubb
@ 2011-11-30 6:15 ` Stefan Weil
2011-11-30 6:20 ` Peter Chubb
4 siblings, 1 reply; 14+ messages in thread
From: Stefan Weil @ 2011-11-30 6:15 UTC (permalink / raw)
To: Peter Chubb; +Cc: Peter Maydell, qemu-devel, Andreas Färber
Am 30.11.2011 04:36, schrieb Peter Chubb:
> Changes since last patchset:
> * All files now under GPL version 2 or later (I've talked with
> OK-Labs and they've agreed).
hw/imx_serial.c is still GPL 2 only. I did not review the rest.
> * `DPRINTF' like macro for printing out guest kernel and qemu
> implementation errors
> * Fixed bugs in avic implementation, as found by PMM
> * Use a static initialiser and sysbus_register_withprop() instead of
> calls to sysbus_register() adn vmstate_register()
> * Fixed bugs in imx_timer.c as noted by PMM and Andreas
Could you please use 'git send-email' to send the patches?
Patches which are appended to a mail make review and
answering difficult.
Regards,
Stefan Weil
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support
2011-11-30 6:15 ` [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Stefan Weil
@ 2011-11-30 6:20 ` Peter Chubb
0 siblings, 0 replies; 14+ messages in thread
From: Peter Chubb @ 2011-11-30 6:20 UTC (permalink / raw)
To: Stefan Weil; +Cc: Peter Maydell, Peter Chubb, qemu-devel, Andreas Färber
>>>>> "Stefan" == Stefan Weil <sw@weilnetz.de> writes:
Stefan> Am 30.11.2011 04:36, schrieb Peter Chubb:
>> Changes since last patchset: * All files now under GPL version 2 or
>> later (I've talked with OK-Labs and they've agreed).
Stefan> hw/imx_serial.c is still GPL 2 only. I did not review the
Stefan> rest.
Missed one, sorry.
>> * `DPRINTF' like macro for printing out guest kernel and qemu
>> implementation errors * Fixed bugs in avic implementation, as found
>> by PMM * Use a static initialiser and sysbus_register_withprop()
>> instead of calls to sysbus_register() adn vmstate_register() *
>> Fixed bugs in imx_timer.c as noted by PMM and Andreas
Stefan> Could you please use 'git send-email' to send the patches?
Stefan> Patches which are appended to a mail make review and answering
Stefan> difficult.
I used quilt mail --send
Peter C
--
Dr Peter Chubb http://www.gelato.unsw.edu.au peterc AT gelato.unsw.edu.au
http://www.ertos.nicta.com.au ERTOS within National ICT Australia
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series.
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series Peter Chubb
@ 2011-12-01 16:55 ` Peter Maydell
2011-12-01 16:56 ` Peter Maydell
2011-12-06 1:03 ` Peter Chubb
0 siblings, 2 replies; 14+ messages in thread
From: Peter Maydell @ 2011-12-01 16:55 UTC (permalink / raw)
To: Peter Chubb; +Cc: Hans Jang, Adam Clench, qemu-devel, Andreas Färber
On 30 November 2011 03:36, Peter Chubb <peter.chubb@nicta.com.au> wrote:
Commit messages should be formatted with a short summary line,
then a blank line, then a more detailed description. You've
put everything into one extremely long summary line here, which
looks odd in git log. Try:
===begin===
hw/imx_serial: Implement the FreeScale i.MX UART
Implement the FreeScale i.MX UART. This uart is used in a variety
of SoCs, including some by Motorola, as well as in the FreeScale
i.MX series.
Signed-off-by: &c.
===endit===
Similarly for the other patches in this series.
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: Adam Clench <adamc@ok-labs.com>
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> ---
> Makefile.target | 1
> hw/imx_serial.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 321 insertions(+)
> create mode 100644 hw/imx_serial.c
>
> Index: qemu-working/hw/imx_serial.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ qemu-working/hw/imx_serial.c 2011-11-30 13:38:24.434778115 +1100
> @@ -0,0 +1,320 @@
> +/*
> + * IMX31 UARTS
> + *
> + * Copyright (c) 2008 OKL
> + * Originally Written by Hans Jiang
> + * Copyright (c) 2011 NICTA Pty Ltd.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
Still GPL v2 only.
> + *
> + * This is a `bare-bones' implementation of the IMX series serial ports.
> + * TODO:
> + * -- implement FIFOs. The real hardware has 32 word transmit
> + * and receive FIFOs; we currently use a 1-char buffer
> + * -- implement DMA
> + * -- implement BAUD-rate and modem lines, for when the backend
> + * is a real serial device.
> + */
> +
> +#include "hw.h"
> +#include "sysbus.h"
> +#include "qemu-char.h"
> +
> +//#define DEBUG_SERIAL 1
> +
> +#ifdef DEBUG_SERIAL
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_serial: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +/*
> + * Define to 1 for messages about attempts to
> + * access unimplemented registers or similar.
> + */
> +#define DEBUG_IMPLEMENTATION 1
> +#if DEBUG_IMPLEMENTATION
> +# define IPRINTF(fmt, args...) \
> + do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
> +#else
> +# define IPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +typedef struct {
> + SysBusDevice busdev;
> + MemoryRegion iomem;
> + int32_t readbuff;
> +
> + uint32_t usr1;
> + uint32_t usr2;
> + uint32_t ucr1;
> + uint32_t uts1;
> +
> + uint32_t ubrm;
The MCIMX31RM calls this UBMR, not UBRM...
> + uint32_t ubrc;
> +
> + qemu_irq irq;
> + CharDriverState *chr;
> +} imx_state;
> +
> +static const VMStateDescription vmstate_imx_serial = {
> + .name = "imx-serial",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_INT32(readbuff, imx_state),
> + VMSTATE_UINT32(usr1, imx_state),
> + VMSTATE_UINT32(usr2, imx_state),
> + VMSTATE_UINT32(ucr1, imx_state),
> + VMSTATE_UINT32(uts1, imx_state),
> + VMSTATE_UINT32(ubrm, imx_state),
> + VMSTATE_UINT32(ubrc, imx_state),
> + VMSTATE_END_OF_LIST()
> + },
> +};
> +
> +
> +#define URXD_CHARRDY (1<<15) /* character read is valid */
> +
> +#define USR1_TRDY (1<<13) /* Xmitter ready */
> +#define USR1_RRDY (1<<9) /* receiver ready */
> +
> +#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
> +#define USR2_TXDC (1<<3) /* Transmission complete */
> +#define USR2_RDR (1<<0) /* Receive data ready */
> +
> +#define UCR1_TRDYEN (1<<13)
> +#define UCR1_RRDYEN (1<<9)
> +#define UCR1_TXMPTYEN (1<<6)
> +#define UCR1_UARTEN (1<<0)
> +
> +#define UTS1_TXEMPTY (1<<6)
> +#define UTS1_RXEMPTY (1<<5)
> +#define UTS1_TXFULL (1<<4)
> +#define UTS1_RXFULL (1<<3)
> +
> +static void imx_update(imx_state *s)
> +{
> + uint32_t flags;
> +
> + flags = ((s->usr1 & s->ucr1)) & (USR1_TRDY|USR1_RRDY);
> + if (!(s->ucr1 & UCR1_TXMPTYEN)) {
> + flags &= ~USR1_TRDY;
> + }
> +
> + if (flags) {
> + DPRINTF("imx_serial: raising interrupt\n");
> + }
> +
> + qemu_set_irq(s->irq, !!flags);
> +}
> +
> +static void imx_serial_reset(DeviceState *dev)
> +{
> + imx_state *s = container_of(dev, imx_state, busdev.qdev);
> +
> + s->usr1 = USR1_TRDY;
My copy of the MCIMX31RM says we also set RXDS on reset.
> + s->usr2 = USR2_TXFE | USR2_TXDC;
Presumably we don't set DCDIN here because we haven't implemented
the modem control signals yet?
> + s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
> + s->ubrm = 0;
> + s->ubrc = 0;
RM says the reset value for UBRC is 0x4.
You also need to reset s->ucr1. (If you want to retain that
hack in the init function then you still need to reset the other
bits even if you don't allow reset to clear UARTEN.)
> + s->readbuff = 0;
> +
> + imx_update(s);
This will call qemu_set_irq() which is a bad idea in a reset function.
Don't call imx_update() here, instead call it after calling imx_serial_reset()
from your register write function.
> +}
> +
> +static uint64_t imx_serial_read(void *opaque, target_phys_addr_t offset,
> + unsigned size)
> +{
> + 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;
> + if (!(s->uts1 & UTS1_RXEMPTY)) {
> + /* Character is valid */
> + c |= URXD_CHARRDY;
> + s->usr1 &= ~USR1_RRDY;
> + s->usr2 &= ~USR2_RDR;
> + s->uts1 |= UTS1_RXEMPTY;
> + imx_update(s);
> + qemu_chr_accept_input(s->chr);
> + }
> + return c;
> +
> + case 0x20: /* UCR1 */
> + return s->ucr1;
> +
> + case 0x21: /* UCR2 */
> + return 1; /* reset complete */
UCR2_SRST.
> +
> + case 0x25: /* USR1 */
> + return s->usr1;
> +
> + case 0x26: /* USR2 */
> + return s->usr2;
> +
> + case 0x2A: /* BRM Modulator */
> + return s->ubrm;
> +
> + case 0x2B: /* Baud Rate Count */
> + return s->ubrc;
> +
> + case 0x2d: /* UTS1 */
> + return s->uts1;
> +
> + case 0x22: /* UCR3 */
> + case 0x23: /* UCR4 */
> + case 0x24: /* UFCR */
> + case 0x29: /* BRM Incremental */
> + return 0x0; /* TODO */
> +
> + default:
> + IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
> + return 0;
> + }
> +}
> +
> +static void imx_serial_write(void *opaque, target_phys_addr_t offset,
> + uint64_t value, unsigned size)
> +{
> + imx_state *s = (imx_state *)opaque;
> + unsigned char ch;
> +
> + DPRINTF("write(offset=%x, value = %x)\n", offset >> 2, (unsigned int)value);
> + switch (offset >> 2) {
> + case 0x10: /* UTXD */
> + ch = value;
> + if (s->chr) {
> + qemu_chr_fe_write(s->chr, &ch, 1);
> + }
> + s->usr1 &= ~USR1_TRDY;
> + imx_update(s);
> + s->usr1 |= USR1_TRDY;
> + imx_update(s);
> + break;
> +
> + case 0x20: /* UCR1 */
> + s->ucr1 = value;
RM says the top 16 bits of UCR1 are read-only.
> + DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
> + imx_update(s);
> + break;
> +
> + case 0x21: /* UCR2 */
> + if (!(value & 1)) {
UCR2_SRST, not 1.
> + imx_serial_reset(&s->busdev.qdev);
> + }
This doesn't implement writing to any of the other bits of
UCR2.
> + break;
> +
> + case 0x26: /* USR2 */
> + /*
> + * Writing 1 to some bits clears them; all other
> + * values are ignored
> + */
> + value &= (1<<15) | (1<<13) | (1<<12) | (1<<11) | (1<<10)|
> + (1<<8) | (1<<7) | (1<<6) | (1<<4) | (1<<2) | (1<<1);
define and use USR2_FOO named constants.
> + s->usr2 &= ~value;
> + break;
> +
> + /* Linux expects to see what it writes here. */
> + /* We don't currently alter the baud rate */
> + case 0x29: /* UBIR */
> + s->ubrc = value;
Top 16 bits shouldn't be writable.
> + break;
> +
> + case 0x2a: /* UBRM */
> + s->ubrm = value;
Ditto.
> + break;
> +
> + case 0x2d: /* UTS1 */
> + case 0x22: /* UCR3 */
> + case 0x23: /* UCR4 */
> + case 0x24: /* UFCR */
> + case 0x25: /* USR1 */
> + case 0x2c: /* BIPR1 */
> + /* TODO */
No IPRINTF() ?
> + break;
> +
> + default:
> + IPRINTF("imx_serial_write: Bad offset 0x%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 const struct MemoryRegionOps imx_serial_ops = {
> + .read = imx_serial_read,
> + .write = imx_serial_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static int imx_serial_init(SysBusDevice *dev)
> +{
> + imx_state *s = FROM_SYSBUS(imx_state, dev);
> +
> + memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
> + sysbus_init_mmio_region(dev, &s->iomem);
> + sysbus_init_irq(dev, &s->irq);
> + s->chr = qdev_init_chardev(&dev->qdev);
> + /*
> + * enable the uart on boot, so messages from the linux decompresser
> + * are visible. On real hardware this is done by the boot rom
> + * before anything else is loaded.
> + */
> + s->ucr1 = UCR1_UARTEN;
> +
> + if (s->chr) {
> + qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
> + imx_event, s);
> + }
> + return 0;
> +}
> +
> +static SysBusDeviceInfo imx_serial_info = {
> + .qdev.name = "imx_serial",
> + .qdev.desc = "i.MX series UART",
> + .qdev.size = sizeof (imx_state),
Unnecessary space (and checkpatch will complain).
> + .qdev.vmsd = &vmstate_imx_serial,
> + .qdev.reset = imx_serial_reset,
> + .init = imx_serial_init,
> +};
> +
> +static void imx_serial_register_devices(void)
> +{
> + sysbus_register_withprop(&imx_serial_info);
> +}
> +
> +device_init(imx_serial_register_devices)
> Index: qemu-working/Makefile.target
> ===================================================================
> --- qemu-working.orig/Makefile.target 2011-11-30 13:38:19.886754597 +1100
> +++ qemu-working/Makefile.target 2011-11-30 13:38:24.434778115 +1100
> @@ -361,20 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
> obj-arm-y += z2.o
> obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
> obj-arm-y += framebuffer.o
> obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
> obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
> obj-arm-y += syborg_virtio.o
> obj-arm-y += vexpress.o
> obj-arm-y += strongarm.o
> obj-arm-y += collie.o
> obj-arm-y += pl041.o lm4549.o
> +obj-arm-y += imx_serial.o
>
> obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
> obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
> obj-sh4-y += ide/mmio.o
>
> obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
> obj-m68k-y += m68k-semi.o dummy_m68k.o
>
> obj-s390x-y = s390-virtio-bus.o s390-virtio.o
This is OK, but whatever you're generating patches with seems to have
produced an awful lot of context lines here :-)
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series.
2011-12-01 16:55 ` Peter Maydell
@ 2011-12-01 16:56 ` Peter Maydell
2011-12-01 19:26 ` Peter Chubb
2011-12-06 1:03 ` Peter Chubb
1 sibling, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2011-12-01 16:56 UTC (permalink / raw)
To: Peter Chubb; +Cc: Hans Jang, Adam Clench, qemu-devel, Andreas Färber
On 1 December 2011 16:55, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 30 November 2011 03:36, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Is this email address correct? Trying to send this email got me:
550 550 <hsjang@ok-labs.com>... User not known (state 17).
>> Signed-off-by: Adam Clench <adamc@ok-labs.com>
>> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run.
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run Peter Chubb
@ 2011-12-01 17:11 ` Peter Maydell
0 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2011-12-01 17:11 UTC (permalink / raw)
To: Peter Chubb; +Cc: Hans Jang, Adam Clench, qemu-devel, Andreas Färber
On 30 November 2011 03:36, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: Adam Clench <adamc@ok-labs.com>
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> ---
> Makefile.target | 2
> hw/imx_timer.c | 460 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 461 insertions(+), 1 deletion(-)
> create mode 100644 hw/imx_timer.c
>
> Index: qemu-working/hw/imx_timer.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ qemu-working/hw/imx_timer.c 2011-11-30 13:38:25.818785258 +1100
> @@ -0,0 +1,460 @@
> +/*
> + * IMX31 Timer
> + *
> + * Copyright (c) 2008 OKL
> + * Copyright (c) 2011 NICTA Pty Ltd
> + * Originally Written by Hans Jiang
> + * Updated by Peter Chubb
> + *
> + * This code is licenced under GPL version 2 or later. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "hw.h"
> +#include "qemu-timer.h"
> +#include "sysbus.h"
> +
> +//#define DEBUG_TIMER 1
> +
> +#ifdef DEBUG_TIMER
> +# define DPRINTF(fmt, args...) \
> + do { printf("imx_timer: " fmt , ##args); } while (0)
> +#else
> +# define DPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +/*
> + * Define to 1 for messages about attempts to
> + * access unimplemented registers or similar.
> + */
> +#define DEBUG_IMPLEMENTATION 1
> +#if DEBUG_IMPLEMENTATION
> +# define IPRINTF(fmt, args...) \
> + do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
> +#else
> +# define IPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +/*
> + * GPT : General purpose timer
> + */
> +
> +#define TIMER_MAX 0xFFFFFFFFUL
> +#define GPT_FREQ 50000000 /* Hz == 50 MHz */
> +
> +/* Control register. Not all of these bits have any effect (yet) */
> +#define GPT_CR_EN (1 << 0) /* GPT Enable */
> +#define GPT_CR_ENMODE (1 << 1) /* GPT Enable Mode */
> +#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */
> +#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */
> +#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */
> +#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */
> +#define GPT_CR_CLKSRC (7 << 6) /* Clock source select (3 bits) */
> +#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */
> +#define GPT_CR_SWR (1 << 15)
> +#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */
> +#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */
> +#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
> +#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
> +#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
> +#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */
> +#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */
> +#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */
> +
> +#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 {
> + SysBusDevice busdev;
> + QEMUTimer *timer;
> + MemoryRegion iomem;
> + 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;
> +
> +static const VMStateDescription vmstate_imxg_timer = {
> + .name = "imxg-timer",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(cr, imxg_timer_state),
> + VMSTATE_UINT32(sr, imxg_timer_state),
> + VMSTATE_UINT32(ir, imxg_timer_state),
> + VMSTATE_UINT32(cnt, imxg_timer_state),
> + VMSTATE_UINT32(ocr1, imxg_timer_state),
> + VMSTATE_TIMER(timer, imxg_timer_state),
Missing 'pr' and 'waiting_rov' ?
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +
> +/* Check all active timers, and schedule the next timer interrupt. */
> +static void imxg_timer_update(imxg_timer_state *s)
> +{
> + uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
> +
> + if ((s->cr & GPT_CR_EN) && flags) {
> + 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/1000000,
> + 1000)) % 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 + diff_cnt * 1000 / (GPT_FREQ/1000000));
You haven't explained why this uses raw qemu timers but
the enhanced timer later in the file uses ptimers, why
doing a % 0xffffffff makes sense, etc.
Stopped review here.
> +}
> +
> +static uint64_t imxg_timer_read(void *opaque, target_phys_addr_t offset,
> + unsigned size)
> +{
> + 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;
> + }
> +
> + IPRINTF("imxg_timer_read: Bad offset %x\n",
> + (int)offset >> 2);
> + return 0;
> +}
> +
> +static void imxg_timer_reset(DeviceState *dev)
> +{
> + imxg_timer_state *s = container_of(dev, imxg_timer_state, busdev.qdev);
> +
> + s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
> + s->sr = 0;
> + s->pr = 0;
> + s->ir = 0;
> + s->cnt = 0;
> + s->ocr1 = 0;
> + imxg_timer_update_count(s);
> + imxg_timer_update(s);
> +}
> +
> +static void imxg_timer_write(void *opaque, target_phys_addr_t offset,
> + uint64_t value, unsigned size)
> +{
> + imxg_timer_state *s = (imxg_timer_state *)opaque;
> + DPRINTF("g-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
> + (unsigned int)value);
> +
> + switch (offset >> 2) {
> + case 0: /* CR */
> + if (value & GPT_CR_SWR) { /* force reset */
> + value &= ~GPT_CR_SWR;
> + imxg_timer_reset(&s->busdev.qdev);
> + }
> + if (!(s->cr & GPT_CR_EN) && (value & GPT_CR_EN)) {
> + if (value & GPT_CR_ENMODE) {
> + s->cnt = 0;
> + }
> + imxg_timer_run(s, s->ocr1);
> + } else 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:
> + s->ocr1 = value;
> + if (s->cr & GPT_CR_EN) {
> + imxg_timer_run(s, s->ocr1);
> + }
> + return;
> +
> + default:
> + IPRINTF("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;
> +
> + DPRINTF("imxg_timer_timeout\n");
> + 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 const MemoryRegionOps imxg_timer_ops = {
> + .read = imxg_timer_read,
> + .write = imxg_timer_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +
> +static int imxg_timer_init(SysBusDevice *dev)
> +{
> + imxg_timer_state *s = FROM_SYSBUS(imxg_timer_state, dev);
> +
> + sysbus_init_irq(dev, &s->irq);
> + memory_region_init_io(&s->iomem, &imxg_timer_ops,
> + s, "imxg-timer",
> + 0x00001000);
> + sysbus_init_mmio_region(dev, &s->iomem);
> +
> + s->timer = qemu_new_timer_ns(vm_clock, imxg_timer_timeout, s);
> + imxg_timer_reset(&dev->qdev);
> + return 0;
> +}
> +
> +
> +
> +/*
> + * 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 {
> + SysBusDevice busdev;
> + ptimer_state *timer;
> + MemoryRegion iomem;
> + 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 void imxp_timer_reset(DeviceState *dev)
> +{
> + imxp_timer_state *s = container_of(dev, imxp_timer_state, busdev.qdev);
> +
> + s->cr = 0;
> + s->lr = 0;
> + ptimer_stop(s->timer);
> +}
> +
> +static uint64_t imxp_timer_read(void *opaque, target_phys_addr_t offset,
> + unsigned size)
> +{
> + 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);
> + }
> + IPRINTF("imxp_timer_read: Bad offset %x\n",
> + (int)offset >> 2);
> + return 0;
> +}
> +
> +static void imxp_timer_write(void *opaque, target_phys_addr_t offset,
> + uint64_t value, unsigned size)
> +{
> + imxp_timer_state *s = (imxp_timer_state *)opaque;
> + DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
> + (unsigned int)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) {
> + imxp_timer_reset(&s->busdev.qdev);
> + }
> + 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:
> + IPRINTF("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 const MemoryRegionOps imxp_timer_ops = {
> + .read = imxp_timer_read,
> + .write = imxp_timer_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +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_UINT32(cmp, imxp_timer_state),
> + VMSTATE_INT32(int_level, imxp_timer_state),
> + VMSTATE_PTIMER(timer, imxp_timer_state),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static int imxp_timer_init(SysBusDevice *dev)
> +{
> + imxp_timer_state *s = FROM_SYSBUS(imxp_timer_state, dev);
> + QEMUBH *bh;
> +
> + DPRINTF("imxp_timer_init\n");
> +
> + sysbus_init_irq(dev, &s->irq);
> + memory_region_init_io(&s->iomem, &imxp_timer_ops,
> + s, "imxp-timer",
> + 0x00001000);
> + sysbus_init_mmio_region(dev, &s->iomem);
> +
> + bh = qemu_bh_new(imxp_timer_tick, s);
> + s->timer = ptimer_init(bh);
> + imxp_timer_reset(&s->busdev.qdev);
> +
> + return 0;
> +}
> +
> +static SysBusDeviceInfo imx_timerp_info = {
> + .qdev.name = "imx_timerp",
> + .qdev.desc = "i.MX Periodic Timer",
> + .qdev.size = sizeof (imxp_timer_state),
> + .qdev.vmsd = &vmstate_imxp_timer,
> + .qdev.reset = imxp_timer_reset,
> + .init = imxp_timer_init,
> +
> +};
> +
> +static SysBusDeviceInfo imx_timerg_info = {
> + .qdev.name = "imx_timerg",
> + .qdev.desc = "i.MX General Timer",
> + .qdev.size = sizeof (imxg_timer_state),
> + .qdev.vmsd = &vmstate_imxg_timer,
> + .qdev.reset = imxg_timer_reset,
> + .init = imxg_timer_init,
> +};
> +
> +static void imx_timer_register_devices(void)
> +{
> + sysbus_register_withprop(&imx_timerp_info);
> + sysbus_register_withprop(&imx_timerg_info);
> +}
> +
> +device_init(imx_timer_register_devices)
> Index: qemu-working/Makefile.target
> ===================================================================
> --- qemu-working.orig/Makefile.target 2011-11-30 13:38:24.786779925 +1100
> +++ qemu-working/Makefile.target 2011-11-30 13:38:25.818785258 +1100
> @@ -361,21 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
> obj-arm-y += z2.o
> obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
> obj-arm-y += framebuffer.o
> obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
> obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
> obj-arm-y += syborg_virtio.o
> obj-arm-y += vexpress.o
> obj-arm-y += strongarm.o
> obj-arm-y += collie.o
> obj-arm-y += pl041.o lm4549.o
> -obj-arm-y += imx_serial.o
> +obj-arm-y += imx_serial.o imx_timer.o
>
> obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
> obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
> obj-sh4-y += ide/mmio.o
>
> obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
> obj-m68k-y += m68k-semi.o dummy_m68k.o
>
> obj-s390x-y = s390-virtio-bus.o s390-virtio.o
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x Peter Chubb
@ 2011-12-01 17:26 ` Peter Maydell
2011-12-06 1:05 ` Peter Chubb
0 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2011-12-01 17:26 UTC (permalink / raw)
To: Peter Chubb; +Cc: Hans Jang, Adam Clench, qemu-devel, Andreas Färber
On 30 November 2011 03:36, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: Adam Clench <adamc@ok-labs.com>
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> ---
> Makefile.target | 2
> hw/imx_avic.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 379 insertions(+), 1 deletion(-)
> create mode 100644 hw/imx_avic.c
>
> Index: qemu-working/hw/imx_avic.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ qemu-working/hw/imx_avic.c 2011-11-30 13:38:27.070791665 +1100
> @@ -0,0 +1,378 @@
> +/*
> + * IMX31 Vectored Interrupt Controller
> + *
> + * Note this is NOT the PL192 provided by ARM, but
> + * a custom implementation by FreeScale.
> + *
> + * Copyright (c) 2008 OKL
> + * Copyright (c) 2011 NICTA Pty Ltd
> + * Originally Written by Hans Jiang
> + *
> + * This code is licenced under the GPL version 2 or later. See
> + * the COPYING file in the top-level directory.
> + *
> + * TODO: implement vectors and priorities.
Vectors are harder (they require support from the target-arm
core implementation which isn't there) but I think you should
implement priorities. That should be purely internal to this
device, and it would be good not to have yet another interrupt
controller in the tree which doesn't get interrupt priorities
right (the NVIC being our other).
Mostly looks ok otherwise though I haven't prodded it too closely.
> + */
> +
> +#include "hw.h"
> +#include "sysbus.h"
> +#include "host-utils.h"
> +
> +#define DEBUG_INT 1
> +#undef DEBUG_INT /* comment out for debugging */
> +
> +#ifdef DEBUG_INT
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_avic: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +/*
> + * Define to 1 for messages about attempts to
> + * access unimplemented registers or similar.
> + */
> +#define DEBUG_IMPLEMENTATION 1
> +#if DEBUG_IMPLEMENTATION
> +# define IPRINTF(fmt, args...) \
> + do { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
> +#else
> +# define IPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +#define IMX_INT_NUM_IRQS 64
> +
> +/* Interrupt Control Bits */
> +#define ABFLAG (1<<25)
> +#define ABFEN (1<<24)
> +#define NIDIS (1<<22) /* Normal Interrupt disable */
> +#define FIDIS (1<<21) /* Fast interrupt disable */
> +#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
> +#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
> +#define NM (1<<18) /* Normal interrupt mode */
> +
> +
> +#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
> +#define PRIO_WORDS (IMX_INT_NUM_IRQS/PRIO_PER_WORD)
> +
> +typedef struct {
> + SysBusDevice busdev;
> + MemoryRegion iomem;
> + uint64_t pending;
> + uint64_t enabled;
> + uint64_t is_fiq;
> + uint32_t intcntl;
> + uint32_t intmask;
> + qemu_irq irq;
> + qemu_irq fiq;
> + uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
> +} imx_int_state;
> +
> +static const VMStateDescription vmstate_imx_avic = {
> + .name = "imx-avic",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .minimum_version_id_old = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT64(pending, imx_int_state),
> + VMSTATE_UINT64(enabled, imx_int_state),
> + VMSTATE_UINT64(is_fiq, imx_int_state),
> + VMSTATE_UINT32(intcntl, imx_int_state),
> + VMSTATE_UINT32(intmask, imx_int_state),
> + VMSTATE_UINT32_ARRAY(prio, imx_int_state, PRIO_WORDS),
> + VMSTATE_END_OF_LIST()
> + },
> +};
> +
> +
> +
> +static inline int imx_int_prio(imx_int_state *s, int irq)
> +{
> + uint32_t word = irq / PRIO_PER_WORD;
> + uint32_t part = 4 * (irq % PRIO_PER_WORD);
> + return 0xf & (s->prio[word] >> part);
> +}
> +
> +static inline void imx_int_set_prio(imx_int_state *s, int irq, int prio)
> +{
> + uint32_t word = irq / PRIO_PER_WORD;
> + uint32_t part = 4 * (irq % PRIO_PER_WORD);
> + uint32_t mask = ~(0xf << part);
> + s->prio[word] &= mask;
> + s->prio[word] |= prio << part;
> +}
> +
> +/* Update interrupts. */
> +static void imx_int_update(imx_int_state *s)
> +{
> + int i;
> + uint64_t new = s->pending;
> + uint64_t flags;
> +
> + flags = new & s->enabled & s->is_fiq;
> + qemu_set_irq(s->fiq, !!flags);
> +
> + flags = new & s->enabled & ~s->is_fiq;
> + if (!flags || (s->intmask == 0x1f)) {
> + qemu_set_irq(s->irq, !!flags);
> + return;
> + }
> +
> + /*
> + * Take interrupt if prio lower than the value of intmask
> + * (should really take highest priority interrupt here,
> + * but that would involve processing interrupt sources
> + * in priority order)
> + */
> + for (i = 0; i < IMX_INT_NUM_IRQS; i++) {
> + if (flags & (1UL << i)) {
> + if (imx_int_prio(s, i) > s->intmask) {
> + qemu_set_irq(s->irq, 1);
> + return;
> + }
> + }
> + }
> + qemu_set_irq(s->irq, 0);
> +}
> +
> +static void imx_int_set_irq(void *opaque, int irq, int level)
> +{
> + imx_int_state *s = (imx_int_state *)opaque;
> +
> + if (level) {
> + s->pending |= (1ULL << irq);
> + } else {
> + s->pending &= ~(1ULL << irq);
> + }
> +
> + imx_int_update(s);
> +}
> +
> +
> +static uint64_t imx_int_read(void *opaque,
> + target_phys_addr_t offset, unsigned size)
> +{
> + imx_int_state *s = (imx_int_state *)opaque;
> +
> +
> + DPRINTF("read(offset = 0x%x)\n", offset >> 2);
> + switch (offset >> 2) {
> + case 0: /* INTCNTL */
> + return s->intcntl;
> +
> + case 1: /* Normal Interrupt Mask Register, NIMASK */
> + return s->intmask;
> +
> + case 2: /* Interrupt Enable Number Register, INTENNUM */
> + case 3: /* Interrupt Disable Number Register, INTDISNUM */
> + return 0;
> +
> + case 4: /* Interrupt Enabled Number Register High */
> + return s->enabled >> 32;
> +
> + case 5: /* Interrupt Enabled Number Register Low */
> + return s->enabled & 0xffffffffULL;
> +
> + case 6: /* Interrupt Type Register High */
> + return s->is_fiq >> 32;
> +
> + case 7: /* Interrupt Type Register Low */
> + return s->is_fiq & 0xffffffffULL;
> +
> + case 8: /* Normal Interrupt Priority Register 7 */
> + case 9: /* Normal Interrupt Priority Register 6 */
> + case 10:/* Normal Interrupt Priority Register 5 */
> + case 11:/* Normal Interrupt Priority Register 4 */
> + case 12:/* Normal Interrupt Priority Register 3 */
> + case 13:/* Normal Interrupt Priority Register 2 */
> + case 14:/* Normal Interrupt Priority Register 1 */
> + case 15:/* Normal Interrupt Priority Register 0 */
> + return s->prio[15-(offset>>2)];
> +
> + case 16: /* Normal interrupt vector and status register */
> + {
> + /*
> + * Note: this is supposed to return highest priority
> + * outstanding interrupt
> + */
> + uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
> + int i = ctz64(flags);
> + if (i < 64) {
> + imx_int_set_irq(opaque, i, 0);
> + return i << 16 | imx_int_prio(s, i);
> + }
> + return 0xffffffffULL;
> + }
> + case 17:/* Fast Interrupt vector and status register */
> + {
> + uint64_t flags = s->pending & s->enabled & s->is_fiq;
> + int i = ctz64(flags);
> + if (i < 64) {
> + imx_int_set_irq(opaque, i, 0);
> + return i;
> + }
> + return 0xffffffffULL;
> + }
> + case 18:/* Interrupt source register high */
> + return s->pending >> 32;
> +
> + case 19:/* Interrupt source register low */
> + return s->pending & 0xffffffffULL;
> +
> + case 20:/* Interrupt Force Register high */
> + case 21:/* Interrupt Force Register low */
> + return 0;
> +
> + case 22:/* Normal Interrupt Pending Register High */
> + return (s->pending & s->enabled & ~s->is_fiq) >> 32;
> +
> + case 23:/* Normal Interrupt Pending Register Low */
> + return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
> +
> + case 24: /* Fast Interrupt Pending Register High */
> + return (s->pending & s->enabled & s->is_fiq) >> 32;
> +
> + case 25: /* Fast Interrupt Pending Register Low */
> + return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
> +
> + case 0x40: /* AVIC vector 0, use for WFI WAR */
> + return 0x4;
> +
> + default:
> + IPRINTF("imx_int_read: Bad offset 0x%x\n", (int)offset);
> + return 0;
> + }
> +}
> +
> +static void imx_int_write(void *opaque, target_phys_addr_t offset,
> + uint64_t val, unsigned size)
> +{
> + imx_int_state *s = (imx_int_state *)opaque;
> +
> + /* Vector Registers not yet supported */
> + if (offset >= 0x100 && offset <= 0x2fc) {
> + DPRINTF("imx_int_write to vector register %d\n",
> + (offset - 0x100) >> 2);
> + return;
> + }
> +
> + DPRINTF("imx_int_write(0x%x) = %x\n",
> + (unsigned int)offset>>2, (unsigned int)val);
> + switch (offset >> 2) {
> + case 0: /* Interrupt Control Register, INTCNTL */
> + s->intcntl = val & (ABFLAG | ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
ABFLAG is write-one-to-clear if ABFEN is set.
> + break;
> +
> + case 1: /* Normal Interrupt Mask Register, NIMASK */
> + s->intmask = val & 0x1f;
> + break;
> +
> + case 2: /* Interrupt Enable Number Register, INTENNUM */
> + DPRINTF("enable(%d)\n", (int)val);
> + val &= 0x3f;
> + s->enabled |= (1ULL << val);
> + break;
> +
> + case 3: /* Interrupt Disable Number Register, INTDISNUM */
> + DPRINTF("disable(%d)\n", (int)val);
> + val &= 0x3f;
> + s->enabled &= ~(1ULL << val);
> + break;
> +
> + case 4: /* Interrupt Enable Number Register High */
> + s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
> + break;
> +
> + case 5: /* Interrupt Enable Number Register Low */
> + s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
> + break;
> +
> + case 6: /* Interrupt Type Register High */
> + s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
> + break;
> +
> + case 7: /* Interrupt Type Register Low */
> + s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
> + break;
> +
> + case 8: /* Normal Interrupt Priority Register 7 */
> + case 9: /* Normal Interrupt Priority Register 6 */
> + case 10:/* Normal Interrupt Priority Register 5 */
> + case 11:/* Normal Interrupt Priority Register 4 */
> + case 12:/* Normal Interrupt Priority Register 3 */
> + case 13:/* Normal Interrupt Priority Register 2 */
> + case 14:/* Normal Interrupt Priority Register 1 */
> + case 15:/* Normal Interrupt Priority Register 0 */
> + s->prio[15-(offset>>2)] = val;
> + break;
> +
> + /* Read-only registers, writes ignored */
> + case 16:/* Normal Interrupt Vector and Status register */
> + case 17:/* Fast Interrupt vector and status register */
> + case 18:/* Interrupt source register high */
> + case 19:/* Interrupt source register low */
> + return;
> +
> + case 20:/* Interrupt Force Register high */
> + s->pending = (s->pending & 0xffffffffULL) | (val << 32);
> + break;
> +
> + case 21:/* Interrupt Force Register low */
> + s->pending = (s->pending & 0xffffffff00000000ULL) | val;
> + break;
> +
> + case 22:/* Normal Interrupt Pending Register High */
> + case 23:/* Normal Interrupt Pending Register Low */
> + case 24: /* Fast Interrupt Pending Register High */
> + case 25: /* Fast Interrupt Pending Register Low */
> + return;
> +
> + default:
> + IPRINTF("imx_int_write: Bad offset %x\n", (int)offset);
> + }
> + imx_int_update(s);
> +}
> +
> +static const MemoryRegionOps imx_int_ops = {
> + .read = imx_int_read,
> + .write = imx_int_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void imx_int_reset(DeviceState *dev)
> +{
> + imx_int_state *s = container_of(dev, imx_int_state, busdev.qdev);
> + s->intmask = 0x1f;
> + s->enabled = 0;
Shouldn't this be resetting more fields than this?
> +}
> +
> +static int imx_int_init(SysBusDevice *dev)
> +{
> + imx_int_state *s = FROM_SYSBUS(imx_int_state, dev);;
> +
> + memory_region_init_io(&s->iomem, &imx_int_ops, s, "imx_int", 0x1000);
> + sysbus_init_mmio_region(dev, &s->iomem);
> +
> + qdev_init_gpio_in(&dev->qdev, imx_int_set_irq, IMX_INT_NUM_IRQS);
> + sysbus_init_irq(dev, &s->irq);
> + sysbus_init_irq(dev, &s->fiq);
> +
> + return 0;
> +}
> +
> +static SysBusDeviceInfo imx_int_info = {
> + .qdev.name = "imx_int",
> + .qdev.desc = "i.MX Advanced Vector Interrupt Controller",
> + .qdev.size = sizeof (imx_int_state),
> + .qdev.reset = imx_int_reset,
> + .qdev.vmsd = &vmstate_imx_avic,
> + .init = imx_int_init,
> +};
> +
> +static void imx_int_register_devices(void)
> +{
> + sysbus_register_withprop(&imx_int_info);
> +}
> +
> +device_init(imx_int_register_devices)
> +
> Index: qemu-working/Makefile.target
> ===================================================================
> --- qemu-working.orig/Makefile.target 2011-11-30 13:38:26.170787074 +1100
> +++ qemu-working/Makefile.target 2011-11-30 13:38:27.070791665 +1100
> @@ -361,21 +361,21 @@ obj-arm-y += mst_fpga.o mainstone.o
> obj-arm-y += z2.o
> obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
> obj-arm-y += framebuffer.o
> obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
> obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
> obj-arm-y += syborg_virtio.o
> obj-arm-y += vexpress.o
> obj-arm-y += strongarm.o
> obj-arm-y += collie.o
> obj-arm-y += pl041.o lm4549.o
> -obj-arm-y += imx_serial.o imx_timer.o
> +obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
>
> obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
> obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
> obj-sh4-y += ide/mmio.o
>
> obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
> obj-m68k-y += m68k-semi.o dummy_m68k.o
>
> obj-s390x-y = s390-virtio-bus.o s390-virtio.o
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series.
2011-12-01 16:56 ` Peter Maydell
@ 2011-12-01 19:26 ` Peter Chubb
0 siblings, 0 replies; 14+ messages in thread
From: Peter Chubb @ 2011-12-01 19:26 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:
Peter> On 1 December 2011 16:55, Peter Maydell
Peter> <peter.maydell@linaro.org> wrote:
>> On 30 November 2011 03:36, Peter Chubb <peter.chubb@nicta.com.au>
>> wrote:
>>> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Peter> Is this email address correct? Trying to send this email got
Peter> me: 550 550 <hsjang@ok-labs.com>... User not known (state 17).
He's left the company and noone knows where he is :-(
Peter> -- PMM
--
Dr Peter Chubb peter DOT chubb AT nicta.com.au
http://www.ertos.nicta.com.au ERTOS within National ICT Australia
All things shall perish from under the sky/Music alone shall live, never to die
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series.
2011-12-01 16:55 ` Peter Maydell
2011-12-01 16:56 ` Peter Maydell
@ 2011-12-06 1:03 ` Peter Chubb
1 sibling, 0 replies; 14+ messages in thread
From: Peter Chubb @ 2011-12-06 1:03 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:
Peter> On 30 November 2011 03:36, Peter Chubb
Peter> <peter.chubb@nicta.com.au> wrote: Commit messages should be
Peter> formatted with a short summary line, then a blank line, then a
Peter> more detailed description. You've put everything into one
Peter> extremely long summary line here, which looks odd in git
Peter> log. Try:
Thanks I've fixed that now.
>> top-level directory.
Peter> Still GPL v2 only.
Fixed.
>> + uint32_t ubrm;
Peter> The MCIMX31RM calls this UBMR, not UBRM...
Fixed.
Peter> My copy of the MCIMX31RM says we also set RXDS on reset.
Fixed.
>> + s->usr2 = USR2_TXFE | USR2_TXDC;
Peter> Presumably we don't set DCDIN here because we haven't
Peter> implemented the modem control signals yet?
Exactly. But there's no harm in setting it, so I've added it in.
>> + s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY; + s->ubrm = 0; +
>> s->ubrc = 0;
Peter> RM says the reset value for UBRC is 0x4.
OK.
Peter> You also need to reset s->ucr1. (If you want to retain that
Peter> hack in the init function then you still need to reset the
Peter> other bits even if you don't allow reset to clear UARTEN.)
OK. Fixed.
>> + s->readbuff = 0;
>> + imx_update(s);
Peter> This will call qemu_set_irq() which is a bad idea in a reset
Peter> function. Don't call imx_update() here, instead call it after
Peter> calling imx_serial_reset() from your register write function.
Does the infrastructure guarantee that any interrupt will be cleared
when the reset function is called?
>> + case 0x21: /* UCR2 */
>> + return 1; /* reset complete */
Peter> UCR2_SRST.
Fixed.
>> case 0x20: /* UCR1 */
>> + s->ucr1 = value;
Peter> RM says the top 16 bits of UCR1 are read-only.
Fixed.
Peter> This doesn't implement writing to any of the other bits of
Peter> UCR2.
No, apart from the TXEN and RXEN bits they're all to do with
>> + case 0x26: /* USR2 */
>> + /*
>> + * Writing 1 to some bits clears them; all other
>> + * values are ignored
>> + */
>> + value &= (1<<15) | (1<<13) | (1<<12) | (1<<11) | (1<<10)|
>> + (1<<8) | (1<<7) | (1<<6) | (1<<4) | (1<<2) | (1<<1);
Peter> define and use USR2_FOO named constants.
Done.
>> UCR3 */ + case 0x23: /* UCR4 */ + case 0x24: /* UFCR */ +
>> case 0x25: /* USR1 */ + case 0x2c: /* BIPR1 */ + /* TODO
>> */
Peter> No IPRINTF() ?
This one gets hit too often.
>> + .qdev.size = sizeof (imx_state),
Peter> Unnecessary space (and checkpatch will complain).
I disagree -- there should be a space between the sizeof operator and
the cast that is its operand. sizeof is not a function; and the
parentheses in this case are part of its operand.
I couldn't find any mention of sizeof in the Coding Style
document. However, I'll go with whatever makes you happier.... (but
note that the current qemu source mixes sizeof (type) and sizeof(type)
all over the place).
Look out for a new patch series real soon now...
Peter C
--
Dr Peter Chubb http://www.gelato.unsw.edu.au peterc AT gelato.unsw.edu.au
http://www.ertos.nicta.com.au ERTOS within National ICT Australia
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x
2011-12-01 17:26 ` Peter Maydell
@ 2011-12-06 1:05 ` Peter Chubb
0 siblings, 0 replies; 14+ messages in thread
From: Peter Chubb @ 2011-12-06 1:05 UTC (permalink / raw)
To: Peter Maydell
Cc: Hans Jang, Adam Clench, Peter Chubb, qemu-devel,
Andreas Färber
>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:
Peter> On 30 November 2011 03:36, Peter Chubb
Peter> <peter.chubb@nicta.com.au> wrote:
>> Signed-off-by: Hans Jang <hsjang@ok-labs.com> Signed-off-by: Adam
>> Clench <adamc@ok-labs.com> Signed-off-by: Peter Chubb
>> <peter.chubb@nicta.com.au>
>> ---
>> Makefile.target | 2 hw/imx_avic.c | 378
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files
>> changed, 379 insertions(+), 1 deletion(-) create mode 100644
>> hw/imx_avic.c
>>
>> Index: qemu-working/hw/imx_avic.c
>> ===================================================================
>> --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++
>> qemu-working/hw/imx_avic.c 2011-11-30 13:38:27.070791665 +1100 @@
>> -0,0 +1,378 @@ +/* + * IMX31 Vectored Interrupt Controller + * + *
>> Note this is NOT the PL192 provided by ARM, but + * a custom
>> implementation by FreeScale. + * + * Copyright (c) 2008 OKL + *
>> Copyright (c) 2011 NICTA Pty Ltd + * Originally Written by Hans
>> Jiang + * + * This code is licenced under the GPL version 2 or
>> later. See + * the COPYING file in the top-level directory. + * +
>> * TODO: implement vectors and priorities.
Peter> Vectors are harder (they require support from the target-arm
Peter> core implementation which isn't there) but I think you should
Peter> implement priorities. That should be purely internal to this
Peter> device, and it would be good not to have yet another interrupt
Peter> controller in the tree which doesn't get interrupt priorities
Peter> right (the NVIC being our other).
OK, I've implemented them, but have no way to test them (because Linux
doesn't use them!)
Peter C
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2011-12-06 1:06 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-30 3:36 [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 1/4] Implement the FreeScale i.MX UART. This uart is used in a variety of SoCs, including some by Motorola, as well as in the FreeScale i.MX series Peter Chubb
2011-12-01 16:55 ` Peter Maydell
2011-12-01 16:56 ` Peter Maydell
2011-12-01 19:26 ` Peter Chubb
2011-12-06 1:03 ` Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 2/4] Implement the timers on the FreeScale i.MX31 SoC. This is not a complete implementation, but gives enough for Linux to boot and run Peter Chubb
2011-12-01 17:11 ` Peter Maydell
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 3/4] Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least to the extent it is used by Linux 3.0.x Peter Chubb
2011-12-01 17:26 ` Peter Maydell
2011-12-06 1:05 ` Peter Chubb
2011-11-30 3:36 ` [Qemu-devel] [PATCH V3 4/4] Board support for Kyoto Micros KZM-ARM11-01, an evaluation board built around the FreeScale i.MX31 Peter Chubb
2011-11-30 6:15 ` [Qemu-devel] [PATCH V3 0/4] i.MX31 and KZM board support Stefan Weil
2011-11-30 6:20 ` Peter Chubb
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).