All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
@ 2011-09-29  2:34 Peter Chubb
  2011-09-29  9:58 ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-09-29  2:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Maydell, Paul Brook, philipo, davidm


This patch was written by David Mirabito.

Properly implement the dual-timer read/write for the sp804 dual timer module.
Based on ARM specs at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: David Mirabito <davidm@ok-labs.com>
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
---
 hw/arm_timer.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 09a4b24..35f4bb5 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -196,12 +196,49 @@ static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
 {
     sp804_state *s = (sp804_state *)opaque;
 
-    /* ??? Don't know the PrimeCell ID for this device.  */
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
-    } else {
+    } 
+    if (offset < 0x40) {
         return arm_timer_read(s->timer[1], offset - 0x20);
     }
+
+    /* Is it one of the test or id registers */
+    switch(offset){
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        return 0;
+
+    /* Timer Peripheral ID Registers, one byte per word:
+     * [11:0]  - Part number    = 0x804
+     * [19:12] - Designer Id    = 0x41   ('A')
+     * [23:20] - Revision       = 1
+     * [31:24] - Configurations = 0
+     */
+    case 0xfe0: /* TimerPeriphID0 */
+        return 0x04;
+    case 0xfe4: /* TimerPeriphID1 */
+        return 0x18;
+    case 0xfe8: /* TimerPeriphID2 */
+        return 0x14;
+    case 0xfec: /* TimerPeriphID3 */
+        return 0x00;
+
+    /* PrimeCell ID Registers = 0xB105F00D */
+    case 0xff0: /* TimerPCellID0 */
+        return 0x0d;
+    case 0xff4: /* TimerPCellID1 */
+        return 0xf0;
+    case 0xff8: /* TimerPCellID2 */
+        return 0x05;
+    case 0xffc: /* TimerPCellID3 */
+        return 0xb1;
+    }
+    cpu_abort (cpu_single_env, "sp804_read: Bad offset %x\n",
+               (int)offset);
+
+    return 0;
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
@@ -211,8 +248,12 @@ static void sp804_write(void *opaque, target_phys_addr_t offset,
 
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
-    } else {
+    } else if (offset < 0x40) {
         arm_timer_write(s->timer[1], offset - 0x20, value);
+    } else {
+        /* Technically we could be writing to the Test Registers, but not likely */
+        cpu_abort (cpu_single_env, "sp804_write: Bad offset %x\n",
+                   (int)offset);
     }
 }
 
@@ -269,8 +310,9 @@ static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
+
     if (n > 3) {
-        hw_error("sp804_read: Bad timer %d\n", n);
+        hw_error("icp_pit_read: Bad timer %d\n", n);
     }
 
     return arm_timer_read(s->timer[n], offset & 0xff);
@@ -284,7 +326,7 @@ static void icp_pit_write(void *opaque, target_phys_addr_t offset,
 
     n = offset >> 8;
     if (n > 3) {
-        hw_error("sp804_write: Bad timer %d\n", n);
+        hw_error("icp_pit_write: Bad timer %d\n", n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);
-- 
1.7.6.3


--
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 related	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-09-29  2:34 [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
@ 2011-09-29  9:58 ` Peter Maydell
  2011-09-30  0:20   ` Peter Chubb
                     ` (2 more replies)
  0 siblings, 3 replies; 45+ messages in thread
From: Peter Maydell @ 2011-09-29  9:58 UTC (permalink / raw)
  To: Peter Chubb; +Cc: davidm, qemu-devel, philipo, Paul Brook

On 29 September 2011 03:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> -    /* ??? Don't know the PrimeCell ID for this device.  */
>     if (offset < 0x20) {
>         return arm_timer_read(s->timer[0], offset);
> -    } else {
> +    }
> +    if (offset < 0x40) {
>         return arm_timer_read(s->timer[1], offset - 0x20);
>   }

if (offset < 0x20) {..} else if (offset < 0x40) {..}
would be consistent with what you did in the write function.

> +    /* Timer Peripheral ID Registers, one byte per word:
> +     * [11:0]  - Part number    = 0x804
> +     * [19:12] - Designer Id    = 0x41   ('A')
> +     * [23:20] - Revision       = 1
> +     * [31:24] - Configurations = 0
> +     */
> +    case 0xfe0: /* TimerPeriphID0 */
> +        return 0x04;
> +    case 0xfe4: /* TimerPeriphID1 */
> +        return 0x18;
> +    case 0xfe8: /* TimerPeriphID2 */
> +        return 0x14;
> +    case 0xfec: /* TimerPeriphID3 */
> +        return 0x00;

[etc]

It's neater to do the 8 ID registers with an array, as the other
pl* devices do -- look at hw/pl061.c:pl061_read() for an example.

> +    cpu_abort (cpu_single_env, "sp804_read: Bad offset %x\n",
> +               (int)offset);

Don't cpu_abort() for something a malicious guest can trigger.
(Yes, we do this in some other devices at the moment, but we
shouldn't be introducing new instances of the problem.)

Maybe we should update the comment that says "docs for
this device don't seem to be available"...

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-09-29  9:58 ` Peter Maydell
@ 2011-09-30  0:20   ` Peter Chubb
  2011-09-30  9:04     ` Peter Maydell
       [not found]   ` <w4y5x6g8gk.wl%peter@chubb.wattle.id.au>
  2011-11-21 22:05   ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
  2 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-09-30  0:20 UTC (permalink / raw)
  To: Peter Maydell; +Cc: davidm, Peter Chubb, qemu-devel, philipo, Paul Brook

Thanks Peter!

Here's a reworked patch.

From 7af8e24d6cbd9170a206b6aaac164e3934312b7c Mon Sep 17 00:00:00 2001
From: David Mirabito <david.mirabito@nicta.com.au>
Date: Fri, 24 Jul 2009 11:43:14 +1000
Subject: [PATCH 53/57] Fix sp804 read/write for second timer.

Properly implement the dual-timer read/write for the sp804 dual timer module.
Based on ARM specs at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: David Mirabito <david.mirabito@nicta.com.au>
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
---
 hw/arm_timer.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 54 insertions(+), 9 deletions(-)

Index: qemu-working/hw/arm_timer.c
===================================================================
--- qemu-working.orig/hw/arm_timer.c	2011-09-29 12:40:24.657526348 +1000
+++ qemu-working/hw/arm_timer.c	2011-09-30 10:15:00.724397699 +1000
@@ -163,64 +163,108 @@ static arm_timer_state *arm_timer_init(u
     s->freq = freq;
     s->control = TIMER_CTRL_IE;
 
     bh = qemu_bh_new(arm_timer_tick, s);
     s->timer = ptimer_init(bh);
     vmstate_register(NULL, -1, &vmstate_arm_timer, s);
     return s;
 }
 
 /* ARM PrimeCell SP804 dual timer module.
-   Docs for this device don't seem to be publicly available.  This
-   implementation is based on guesswork, the linux kernel sources and the
-   Integrator/CP timer modules.  */
+ * Docs at
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
+*/
 
 typedef struct {
     SysBusDevice busdev;
     MemoryRegion iomem;
     arm_timer_state *timer[2];
     int level[2];
     qemu_irq irq;
 } sp804_state;
 
+/*
+ * sp804_id should be:
+ * union {
+ * struct {
+ *   uint32_t PartNumber:12; == 0x804
+ *   uint32_t DesignerID:8; == 'A'
+ *   uint32_t Revision:4; == 1
+ *   uint32_t Configurations:6; == 0
+ * };
+ * uint8_t bytes[4];
+ * };
+ * but that gets into too many byte-ordering and packing issues.
+ */
+static const uint8_t sp804_id[] = {0x04, 0x18, 0x14, 0};
+static const uint8_t sp804_PrimeCellID[] = {0xB1, 0x05, 0xF0, 0x0D};
+
 /* Merge the IRQs from the two component devices.  */
 static void sp804_set_irq(void *opaque, int irq, int level)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     s->level[irq] = level;
     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 }
 
 static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
                            unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
-    /* ??? Don't know the PrimeCell ID for this device.  */
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
-    } else {
+    }
+    if (offset < 0x40) {
         return arm_timer_read(s->timer[1], offset - 0x20);
     }
+
+    /*
+     * Ids are packed into a word, then accessed one byte per word.
+     */
+    /* TimerPeriphID */
+    if (offset >= 0xfe0 && offset <= 0xfec)
+	    return sp804_id[(offset - 0xfe0) >> 2];
+    /* PrimeCellID */
+    if (offset >= 0xff0 && offset <= 0xffc)
+	    return sp804_PrimeCellID[(offset - 0xff0) >> 2]
+
+    switch(offset){
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        return 0;
+
+    }
+
+    hw_error("sp804_read: Bad offset %x\n", (int)offset);
+    return 0;
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
                         uint64_t value, unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
-    } else {
+	return;
+    }
+
+    if (offset < 0x40) {
         arm_timer_write(s->timer[1], offset - 0x20, value);
-    }
+	return;
+    }
+
+    /* Technically we could be writing to the Test Registers, but not likely */
+    hw_error("sp804_write: Bad offset %x\n", (int)offset);
 }
 
 static const MemoryRegionOps sp804_ops = {
     .read = sp804_read,
     .write = sp804_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_sp804 = {
     .name = "sp804",
@@ -262,36 +306,37 @@ typedef struct {
 } icp_pit_state;
 
 static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
                              unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
+
     if (n > 3) {
-        hw_error("sp804_read: Bad timer %d\n", n);
+        hw_error("icp_pit_read: Bad timer %d\n", n);
     }
 
     return arm_timer_read(s->timer[n], offset & 0xff);
 }
 
 static void icp_pit_write(void *opaque, target_phys_addr_t offset,
                           uint64_t value, unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     n = offset >> 8;
     if (n > 3) {
-        hw_error("sp804_write: Bad timer %d\n", n);
+        hw_error("icp_pit_write: Bad timer %d\n", n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);
 }
 
 static const MemoryRegionOps icp_pit_ops = {
     .read = icp_pit_read,
     .write = icp_pit_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-09-30  0:20   ` Peter Chubb
@ 2011-09-30  9:04     ` Peter Maydell
  2011-09-30  9:23       ` Peter Chubb
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2011-09-30  9:04 UTC (permalink / raw)
  To: Peter Chubb; +Cc: davidm, qemu-devel, philipo, Paul Brook

On 30 September 2011 01:20, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Thanks Peter!
>
> Here's a reworked patch.

NB: when you resend patches it's better to send them as completely
fresh emails (via git-send-email or equivalent) because otherwise they're
more of a pain to apply (you end up with random email chatter in the
commit message, usually).

> +/*
> + * sp804_id should be:
> + * union {
> + * struct {
> + *   uint32_t PartNumber:12; == 0x804
> + *   uint32_t DesignerID:8; == 'A'
> + *   uint32_t Revision:4; == 1
> + *   uint32_t Configurations:6; == 0
> + * };
> + * uint8_t bytes[4];
> + * };
> + * but that gets into too many byte-ordering and packing issues.
> + */
> +static const uint8_t sp804_id[] = {0x04, 0x18, 0x14, 0};
> +static const uint8_t sp804_PrimeCellID[] = {0xB1, 0x05, 0xF0, 0x0D};

I disagree with "should be" -- yes, semantically the ID registers
have a number of subfields but for practical purposes they're just
bytes; so I don't think that comment is necessary.
There's no need to split the two sets of ID registers into
different arrays, either -- it just complicates the code.
Also you have the primecell ID values in the wrong order (check
the 'register summary' table in the docs). You want:

static const uint8_t sp804_id[] = { 0x04, 0x18, 0x14, 0, 0x0d, 0xf0,
0x05, 0xb1 };

> +    /*
> +     * Ids are packed into a word, then accessed one byte per word.
> +     */

No, they're just a set of byte registers.

> +    /* TimerPeriphID */
> +    if (offset >= 0xfe0 && offset <= 0xfec)
> +           return sp804_id[(offset - 0xfe0) >> 2];

Coding style requires braces on if statements (plus your indentation
is wrong). If you run your patch through scripts/checkpatch.pl it
will catch this sort of thing.

> +    hw_error("sp804_read: Bad offset %x\n", (int)offset);
> +    return 0;

hw_error() is a fatal error -- don't use it for conditions that
can be triggered by a malicious guest. (And since it's noreturn
there's not much point putting any code after it...)

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-09-30  9:04     ` Peter Maydell
@ 2011-09-30  9:23       ` Peter Chubb
  2011-09-30 10:07         ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-09-30  9:23 UTC (permalink / raw)
  To: Peter Maydell; +Cc: davidm, Peter Chubb, qemu-devel, philipo, Paul Brook

>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:

Peter> On 30 September 2011 01:20, Peter Chubb
Peter> <peter.chubb@nicta.com.au> wrote:
>> Thanks Peter!
>> 
>> Here's a reworked patch.

Peter> NB: when you resend patches it's better to send them as
Peter> completely fresh emails (via git-send-email or equivalent)
Peter> because otherwise they're more of a pain to apply (you end up
Peter> with random email chatter in the commit message, usually).

Thanks for the heads-up. I'll edit the patch in Quilt.

>> +/* + * sp804_id should be: + * union { + * struct { + *   uint32_t
>> PartNumber:12; == 0x804 + *   uint32_t DesignerID:8; == 'A' + *  
>> uint32_t Revision:4; == 1 + *   uint32_t Configurations:6; == 0 + *
>> }; + * uint8_t bytes[4]; + * }; + * but that gets into too many
>> byte-ordering and packing issues.  + */ +static const uint8_t
>> sp804_id[] = {0x04, 0x18, 0x14, 0}; +static const uint8_t
>> sp804_PrimeCellID[] = {0xB1, 0x05, 0xF0, 0x0D};

Peter> I disagree with "should be" -- yes, semantically the ID
Peter> registers have a number of subfields but for practical purposes
Peter> they're just bytes; so I don't think that comment is necessary.
Peter> There's no need to split the two sets of ID registers into
Peter> different arrays, either -- it just complicates the code.  Also
Peter> you have the primecell ID values in the wrong order (check the
Peter> 'register summary' table in the docs). You want:

OK, and thanks.

Peter> static const uint8_t sp804_id[] = { 0x04, 0x18, 0x14, 0, 0x0d,
Peter> 0xf0, 0x05, 0xb1 };

>> +    /* +     * Ids are packed into a word, then accessed one byte
>> per word.  +     */

Peter> No, they're just a set of byte registers.

At word offsets.

>> +    /* TimerPeriphID */ +    if (offset >= 0xfe0 && offset <=
>> 0xfec) +           return sp804_id[(offset - 0xfe0) >> 2];

Peter> Coding style requires braces on if statements (plus your
Peter> indentation is wrong). If you run your patch through
Peter> scripts/checkpatch.pl it will catch this sort of thing.

Thanks.

>> +    hw_error("sp804_read: Bad offset %x\n", (int)offset); +  
>>  return 0;

Peter> hw_error() is a fatal error -- don't use it for conditions that
Peter> can be triggered by a malicious guest. (And since it's noreturn
Peter> there's not much point putting any code after it...)

Is there a better `tell the programmer s/he's done something stupid'
error function?  The plxxx.c files all used hw_error() for bad
offsets.


I shan't be able to get to this again until Tuesday my time.  Expect
another patch then.

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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-09-30  9:23       ` Peter Chubb
@ 2011-09-30 10:07         ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-09-30 10:07 UTC (permalink / raw)
  To: Peter Chubb; +Cc: davidm, qemu-devel, philipo, Paul Brook

On 30 September 2011 10:23, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:
> Peter> hw_error() is a fatal error -- don't use it for conditions that
> Peter> can be triggered by a malicious guest. (And since it's noreturn
> Peter> there's not much point putting any code after it...)
>
> Is there a better `tell the programmer s/he's done something stupid'
> error function?  The plxxx.c files all used hw_error() for bad
> offsets.

Unfortunately there isn't really a good infrastructure for this
kind of error. At the moment we have a mix of hw_error(), printing
to stderr, printing to stderr only if debug macros were enabled at
compile time, and silently ignoring things, all of which have
obvious drawbacks.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH] imx.31 and KZM board support
       [not found]     ` <CAFEAcA8-iByH0xgjkMUo3hvkrLc8NV-Lq4GbHU-d7UoF8GSX-Q@mail.gmail.com>
@ 2011-11-21 21:58       ` Peter Chubb
  2011-11-21 22:45         ` Andreas Färber
                           ` (2 more replies)
  0 siblings, 3 replies; 45+ messages in thread
From: Peter Chubb @ 2011-11-21 21:58 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Peter Chubb, qemu-devel

Hi Peter,
   Please find appended a patch containing initial support for the
   FreeScale i.MX31 and the KZM Arm11 evaluation board.

   The implementation was originally written by Hans Jang and Adam
   Clench of OK-Labs; I've updated it to the current qdev and memory
   region paradigms and implemented enough extra that Linux will boot
   on the patched QEMU using a ram disk.

   The i.MX 31 Serial controller is found in most of the i.MX SoCs;
   the AVIC and timer implementations can also be shared, albeit with
   fewer chips.

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: Adam Clench <adamc@ok-labs.com>
---
 Makefile.target |    1 
 hw/imx_avic.c   |  294 ++++++++++++++++++++++++++++++++++++++
 hw/imx_serial.c |  260 +++++++++++++++++++++++++++++++++
 hw/imx_timer.c  |  430 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/kzm.c        |  159 ++++++++++++++++++++
 5 files changed, 1144 insertions(+)
 create mode 100644 hw/imx_avic.c
 create mode 100644 hw/imx_serial.c
 create mode 100644 hw/imx_timer.c
 create mode 100644 hw/kzm.c

Index: qemu-working/Makefile.target
===================================================================
--- qemu-working.orig/Makefile.target	2011-11-22 08:40:56.380128155 +1100
+++ qemu-working/Makefile.target	2011-11-22 08:42:26.288661513 +1100
@@ -336,20 +336,21 @@ obj-sparc-y = sun4m.o lance.o tcx.o sun4
 obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
 obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
 
 # GRLIB
 obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
 endif
 
 obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
 obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
 obj-arm-y += versatile_pci.o
+obj-arm-y += kzm.o imx_avic.o imx_serial.o imx_timer.o
 obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 obj-arm-y += pl061.o
 obj-arm-y += arm-semi.o
 obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-arm-y += gumstix.o
 obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
 obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
 		omap_gpio.o omap_intc.o omap_uart.o
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-22 08:51:09.733239638 +1100
@@ -0,0 +1,294 @@
+/*
+ * IMX31 Vectored Interrupt Controller
+ *
+ * Note this is NOT the PL192 provided by ARM, but
+ * a custom implementation by FreeScale.
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ *
+ * This code is licenced under the GPL.
+ *
+ * TODO: implement vectors and priorities.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include <string.h> /* ffsll */
+
+#define DEBUG_INT 1
+#undef DEBUG_INT /* comment out for debugging */
+
+#ifdef DEBUG_INT
+#define DPRINTF(fmt, args...) \
+do { printf("imx_int: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+
+#define IMX_INT_NUM_IRQS 64
+
+/* 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 */
+
+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[IMX_INT_NUM_IRQS/(32/4)]; /* Priorities are 4-bits each */
+} imx_int_state;
+
+static inline int imx_int_prio(imx_int_state *s, int irq)
+{
+    uint32_t word = irq / (32/4);
+    uint32_t part = irq % (32/4);
+    return 0xff & (s->prio[word] >> (4 * part));
+}
+
+static inline void imx_int_set_prio(imx_int_state *s, int irq, int prio)
+{
+    uint32_t word = irq / (32/4);
+    uint32_t part = 4 * (irq % (32/4));
+    uint32_t mask = ~(0xff << 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 || likely((s->intmask & 0x1f) == 0x1f)) {
+        qemu_set_irq(s->irq, !!flags);
+        return;
+    }
+    /* Take interrupt if  prio lower than the value of intmask */
+
+    for (i = 0; i < IMX_INT_NUM_IRQS; i++) {
+        if (flags & (1<<i)) {
+            if (imx_int_prio(s, i) > s->intmask) {
+                qemu_set_irq(s->irq, 1);
+                return;
+            }
+        }
+    }
+
+}
+
+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 */
+    {
+        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
+        int i = ffsll(flags);
+        if (i) {
+            imx_int_set_irq(opaque, i-1, 0);
+            return (i-1) << 16;
+        }
+        return 0xFFFF<<16;
+    }
+    case 17:/* Fast Interrupt vector and status register */
+    {
+        uint64_t flags = s->pending & s->enabled & s->is_fiq;
+        int i = ffsll(flags);
+        if (i) {
+            imx_int_set_irq(opaque, i-1, 0);
+            return (i-1) << 16;
+        }
+        return 0xFFFF<<16;
+    }
+    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:
+        printf("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;
+        break;
+    case 1: /* Normal Interrupt Mask Register, NIMASK */
+        s->intmask = val;
+        break;
+    case 2: /* Interrupt Enable Number Register, INTENNUM */
+        DPRINTF("enable(%d)\n", (int)val);
+        s->enabled |= (1ULL << val);
+        break;
+    case 3: /* Interrupt Disable Number Register, INTDISNUM */
+        s->enabled &= ~(1ULL << val);
+        DPRINTF("disabled(%d)\n", (int)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: /* Interrypt 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;
+        return;
+        /* 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:
+        hw_error("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 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);
+
+    s->intmask = 0x1f;
+    s->enabled = 0ULL;
+    return 0;
+}
+
+static void imx_int_register_devices(void)
+{
+    sysbus_register_dev("imx_int", sizeof(imx_int_state),
+                        imx_int_init);
+}
+
+device_init(imx_int_register_devices);
+
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-22 08:49:36.084276219 +1100
@@ -0,0 +1,260 @@
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ *
+ * This code is licenced under the GPL.
+ * 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
+ *  -- 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
+#undef DEBUG_SERIAL /* comment out for debugging */
+
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, args...) \
+do { printf("imx_serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+typedef struct {
+    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;
+
+#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_RDR        (1<<0)    /* Receiove data ready */
+#define USR2_TXDC       (1<<3)    /* Transmission complete */
+
+#define UCR1_UARTEN     (1<<0)
+#define UCR1_RRDYEN     (1<<9)
+#define UCR1_TRDYEN     (1<<13)
+#define UCR1_TXMPTYEN   (1<<6)
+
+#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 (0 == (s->ucr1 & UCR1_TXMPTYEN)) {
+        flags &= ~USR1_TRDY;
+    }
+
+    qemu_set_irq(s->irq, !!flags);
+}
+
+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;
+        s->usr1 &= ~USR1_RRDY;
+        s->usr2 &= ~USR2_RDR;
+        s->uts1 |= UTS1_RXEMPTY;
+        imx_update(s);
+        qemu_chr_accept_input(s->chr);
+        return c | URXD_CHARRDY;
+
+    case 0x20: /* UCR1 */
+        return s->ucr1;
+
+    case 0x21: /* UCR2 */
+        return 1; /* reset complete */
+
+    case 0x25: /* USR1 */
+        imx_update(s);
+        return s->usr1;
+
+    case 0x26: /* USR2 */
+        imx_update(s);
+        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:
+        hw_error("imx_serial_read: bad offset: 0x%x\n", (int)offset);
+        /* Keep gcc happy: notreached */
+        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 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 0x21: /* UCR2 */
+    case 0x2d: /* UTS1 */
+    case 0x22: /* UCR3 */
+    case 0x23: /* UCR4 */
+    case 0x24: /* UFCR */
+    case 0x25: /* USR1 */
+    case 0x2c: /* BIPR1 */
+        /* TODO */
+        break;
+
+    default:
+        hw_error("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);
+
+    s->usr1 = USR1_TRDY;
+    s->usr2 = USR2_TXFE | USR2_TXDC;
+    s->ucr1 = UCR1_TRDYEN | UCR1_RRDYEN | UCR1_UARTEN;
+    s->uts1 = UTS1_RXEMPTY;
+    s->readbuff = 0;
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+                              imx_event, s);
+    }
+    return 0;
+    /* ??? Save/restore.  */
+}
+
+static void imx_serial_register_devices(void)
+{
+    DPRINTF("imx_serial_register_devices\n");
+    sysbus_register_dev("imx_serial", sizeof(imx_state),
+                        imx_serial_init);
+}
+
+device_init(imx_serial_register_devices);
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-22 08:51:12.589269454 +1100
@@ -0,0 +1,430 @@
+/*
+ * IMX31 Timer
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ * Updated by Peter Chubb
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "sysbus.h"
+
+#define DEBUG_TIMER 1
+#undef DEBUG_TIMER  /* comment out for debugging */
+
+#ifdef DEBUG_TIMER
+#   define DPRINTF(fmt, args...) \
+        do { printf("imx_timer: " fmt , ##args); } while (0)
+#else
+#   define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * GPT : General purpose timer
+ */
+
+#define TIMER_MAX  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)
+{
+    /* Update interrupts.  */
+    if ((s->cr & GPT_CR_EN)
+        && (((s->sr & GPT_SR_OF1) && (s->ir & GPT_IR_OF1IE)) ||
+            ((s->sr & GPT_SR_ROV) && (s->ir & GPT_IR_ROVIE)))) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static uint64_t imxg_timer_update_count(imxg_timer_state *s)
+{
+    uint64_t clk = qemu_get_clock_ns(vm_clock);
+
+    s->cnt = ((uint32_t)muldiv64(clk, GPT_FREQ/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));
+/*
+                   clk + muldiv64(get_ticks_per_sec(),
+                                            diff_cnt, GPT_FREQ)
+*/
+}
+
+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;
+    }
+
+    cpu_abort(cpu_single_env, "imxg_timer_read: Bad offset %x\n",
+               (int)offset >> 2);
+}
+
+static void imxg_timer_write(void *opaque, target_phys_addr_t offset,
+                             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;
+            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;
+        }
+        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:
+        cpu_abort(cpu_single_env, "imxg_timer_write: Bad offset %x\n",
+                   (int)offset >> 2);
+    }
+}
+
+static void imxg_timer_timeout(void *opaque)
+{
+    imxg_timer_state *s = (imxg_timer_state *)opaque;
+
+    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);
+    s->cr = 0;
+    s->ir = 0;
+    s->pr = 0;
+    s->ocr1 = 0;
+    imxg_timer_update_count(s);
+
+    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 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);
+    }
+    cpu_abort(cpu_single_env, "imxp_timer_read: Bad offset %x\n",
+               (int)offset >> 2);
+}
+
+static void imxp_timer_write(void *opaque, target_phys_addr_t offset,
+                             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 */
+        if (s->cr & CR_EN) {
+            ptimer_run(s->timer, 0);
+        } else {
+            ptimer_stop(s->timer);
+        }
+        if (s->cr & CR_SWR) {
+            s->cr = 0;
+            s->lr = 0;
+            ptimer_stop(s->timer);
+        }
+        break;
+
+    case 1: /* SR - ACK*/
+        s->int_level = 0;
+        imxp_timer_update(s);
+        break;
+
+    case 2: /* LR - set ticks*/
+        s->lr = value;
+        ptimer_set_freq(s->timer, EPIT_FREQ);
+        ptimer_set_limit(s->timer, value, 1);
+        break;
+
+    case 3: /* CMP */
+        s->cmp = value;
+        break;
+
+    default:
+        cpu_abort(cpu_single_env, "imxp_timer_write: Bad offset %x\n",
+                   (int)offset >> 2);
+    }
+}
+
+static void imxp_timer_tick(void *opaque)
+{
+    imxp_timer_state *s = (imxp_timer_state *)opaque;
+    s->int_level = 1;
+    imxp_timer_update(s);
+}
+
+static 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);
+
+    s->cr = 0;
+    s->lr = 0;
+
+    bh = qemu_bh_new(imxp_timer_tick, s);
+    s->timer = ptimer_init(bh);
+    vmstate_register(&dev->qdev, -1, &vmstate_imxp_timer, s);
+
+    return 0;
+}
+
+static void imx_timer_register_devices(void)
+{
+    DPRINTF("Registering Timers\n");
+    sysbus_register_dev("imx_timerp", sizeof(imxp_timer_state),
+                        imxp_timer_init);
+    sysbus_register_dev("imx_timerg", sizeof(imxg_timer_state),
+                        imxg_timer_init);
+}
+
+
+device_init(imx_timer_register_devices);
Index: qemu-working/hw/kzm.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu-working/hw/kzm.c	2011-11-22 08:42:26.292661540 +1100
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ * 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)
+
+/* Board init.  */
+
+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]) {
+        printf("serial_hds[3]\n");
+        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 */
+        printf("serial_hds[2]\n");
+        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);

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-09-29  9:58 ` Peter Maydell
  2011-09-30  0:20   ` Peter Chubb
       [not found]   ` <w4y5x6g8gk.wl%peter@chubb.wattle.id.au>
@ 2011-11-21 22:05   ` Peter Chubb
  2011-11-21 23:01     ` Andreas Färber
  2 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-21 22:05 UTC (permalink / raw)
  To: Peter Maydell; +Cc: davidm, Peter Chubb, qemu-devel, philipo, Paul Brook

Hi Peter,
   Here's a fixed patch for the sp804 timer.

Properly implement the dual-timer read/write for the sp804 dual timer module.
Based on ARM specs at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: David Mirabito <david.mirabito@nicta.com.au>
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
---
 hw/arm_timer.c |   45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

Index: qemu-working/hw/arm_timer.c
===================================================================
--- qemu-working.orig/hw/arm_timer.c	2011-11-21 09:05:05.566351984 +1100
+++ qemu-working/hw/arm_timer.c	2011-11-21 09:05:10.582372066 +1100
@@ -163,64 +163,93 @@ static arm_timer_state *arm_timer_init(u
     s->freq = freq;
     s->control = TIMER_CTRL_IE;
 
     bh = qemu_bh_new(arm_timer_tick, s);
     s->timer = ptimer_init(bh);
     vmstate_register(NULL, -1, &vmstate_arm_timer, s);
     return s;
 }
 
 /* ARM PrimeCell SP804 dual timer module.
-   Docs for this device don't seem to be publicly available.  This
-   implementation is based on guesswork, the linux kernel sources and the
-   Integrator/CP timer modules.  */
+ * Docs at
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
+*/
 
 typedef struct {
     SysBusDevice busdev;
     MemoryRegion iomem;
     arm_timer_state *timer[2];
     int level[2];
     qemu_irq irq;
 } sp804_state;
 
+static const uint8_t sp804_ids[] = {
+    /* Timer ID */
+    0x04, 0x18, 0x14, 0,
+    /* PrimeCell ID */
+    0xd, 0xf0, 0x05, 0xb1
+};
+
 /* Merge the IRQs from the two component devices.  */
 static void sp804_set_irq(void *opaque, int irq, int level)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     s->level[irq] = level;
     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 }
 
 static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
                            unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
-    /* ??? Don't know the PrimeCell ID for this device.  */
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
-    } else {
+    }
+    if (offset < 0x40) {
         return arm_timer_read(s->timer[1], offset - 0x20);
     }
+
+    /* TimerPeriphID */
+    if (offset >= 0xfe0 && offset <= 0xffc) {
+        return sp804_ids[(offset - 0xfe0) >> 2];
+    }
+
+    switch (offset) {
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        return 0;
+    }
+
+    hw_error("sp804_read: Bad offset %x\n", (int)offset);
+    return 0;
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
                         uint64_t value, unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
-    } else {
+        return;
+    }
+
+    if (offset < 0x40) {
         arm_timer_write(s->timer[1], offset - 0x20, value);
+        return;
     }
+
+    /* Technically we could be writing to the Test Registers, but not likely */
+    hw_error("sp804_write: Bad offset %x\n", (int)offset);
 }
 
 static const MemoryRegionOps sp804_ops = {
     .read = sp804_read,
     .write = sp804_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_sp804 = {
     .name = "sp804",
@@ -263,35 +292,35 @@ typedef struct {
 
 static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
                              unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
     if (n > 2) {
-        hw_error("sp804_read: Bad timer %d\n", n);
+        hw_error("icp_pit_read: Bad timer %d\n", n);
     }
 
     return arm_timer_read(s->timer[n], offset & 0xff);
 }
 
 static void icp_pit_write(void *opaque, target_phys_addr_t offset,
                           uint64_t value, unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     n = offset >> 8;
     if (n > 2) {
-        hw_error("sp804_write: Bad timer %d\n", n);
+        hw_error("icp_pit_write: Bad timer %d\n", n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);
 }
 
 static const MemoryRegionOps icp_pit_ops = {
     .read = icp_pit_read,
     .write = icp_pit_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };

--
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
--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 21:58       ` [Qemu-devel] [PATCH] imx.31 and KZM board support Peter Chubb
@ 2011-11-21 22:45         ` Andreas Färber
  2011-11-21 23:04           ` Peter Chubb
  2011-11-21 23:41         ` Peter Maydell
  2011-11-22 11:06         ` [Qemu-devel] [PATCH] " Juan Quintela
  2 siblings, 1 reply; 45+ messages in thread
From: Andreas Färber @ 2011-11-21 22:45 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Peter Chubb, qemu-devel

Hi Peter,

Am 21.11.2011 22:58, schrieb Peter Chubb:
> Hi Peter,
>    Please find appended a patch containing initial support for the
>    FreeScale i.MX31 and the KZM Arm11 evaluation board.

Your patch format is a bit unusual.

Please don't include personal messages in the description, keep it in a
format we can apply unchanged with git-am.

git-am complains:

/home/andreas/QEMU/qemu-arm/.git/rebase-apply/patch:43: new blank line
at EOF.
+
warning: 1 line adds whitespace errors.

>    The implementation was originally written by Hans Jang and Adam
>    Clench of OK-Labs; I've updated it to the current qdev and memory
>    region paradigms and implemented enough extra that Linux will boot
>    on the patched QEMU using a ram disk.
> 
>    The i.MX 31 Serial controller is found in most of the i.MX SoCs;
>    the AVIC and timer implementations can also be shared, albeit with
>    fewer chips.
> 
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: Adam Clench <adamc@ok-labs.com>

If as you describe above, you polished up patches originally by OK-Labs
then your SoB should be placed last.

> 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-22 08:51:09.733239638 +1100
> @@ -0,0 +1,294 @@
> +/*
> + * IMX31 Vectored Interrupt Controller
> + *
> + * Note this is NOT the PL192 provided by ARM, but
> + * a custom implementation by FreeScale.
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.

If you can, it would be nice to clarify the "GPL" license:

    ... the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

> + *
> + * TODO: implement vectors and priorities.
> + */
> +
> +#include "hw.h"
> +#include "sysbus.h"
> +#include <string.h> /* ffsll */
> +
> +#define DEBUG_INT 1
> +#undef DEBUG_INT /* comment out for debugging */

Usually we just do //#define DEBUG_...

> +
> +#ifdef DEBUG_INT
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_int: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif

> 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-22 08:49:36.084276219 +1100
> @@ -0,0 +1,260 @@
> +/*
> + * IMX31 UARTS
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.

Dito.

> + * 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
> + *  -- 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
> +#undef DEBUG_SERIAL /* comment out for debugging */

Dito.

> +
> +#ifdef DEBUG_SERIAL
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_serial: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif

> +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);
> +
> +    s->usr1 = USR1_TRDY;
> +    s->usr2 = USR2_TXFE | USR2_TXDC;
> +    s->ucr1 = UCR1_TRDYEN | UCR1_RRDYEN | UCR1_UARTEN;
> +    s->uts1 = UTS1_RXEMPTY;
> +    s->readbuff = 0;
> +    if (s->chr) {
> +        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
> +                              imx_event, s);
> +    }
> +    return 0;
> +    /* ??? Save/restore.  */

What does this comment tell us? :)

> +}

> 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-22 08:51:12.589269454 +1100
> @@ -0,0 +1,430 @@
> +/*
> + * IMX31 Timer
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + * Updated by Peter Chubb
> + *
> + * This code is licenced under the GPL.

Dito.

> + */
> +
> +#include "hw.h"
> +#include "qemu-timer.h"
> +#include "sysbus.h"
> +
> +#define DEBUG_TIMER 1
> +#undef DEBUG_TIMER  /* comment out for debugging */

Dito.

> +
> +#ifdef DEBUG_TIMER
> +#   define DPRINTF(fmt, args...) \
> +        do { printf("imx_timer: " fmt , ##args); } while (0)
> +#else
> +#   define DPRINTF(fmt, args...) do {} while (0)
> +#endif

> Index: qemu-working/hw/kzm.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ qemu-working/hw/kzm.c	2011-11-22 08:42:26.292661540 +1100
> @@ -0,0 +1,159 @@
> +/*
> + * 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.

Dito.

> + * 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
> +     */

Nice overview!

> +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";

[ My "favorite" CPU... ;) ]

> +    }
> +
> +    env = cpu_init(cpu_model);
> +    if (!env) {
> +        fprintf(stderr, "Unable to find CPU definition\n");
> +        exit(1);
> +    }

My sharp eye also spotted an | without spaces somewhere. If you haven't
already, try running scripts/checkpatch.pl.

Regards,
Andreas

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-11-21 22:05   ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
@ 2011-11-21 23:01     ` Andreas Färber
  2011-11-22  0:20       ` [Qemu-devel] [PATCH] [ARM] fix function names in error messages in arm_timer.c Peter Chubb
                         ` (2 more replies)
  0 siblings, 3 replies; 45+ messages in thread
From: Andreas Färber @ 2011-11-21 23:01 UTC (permalink / raw)
  To: Peter Chubb
  Cc: Peter Maydell, davidm, qemu-devel, Peter Chubb, Paul Brook, philipo

Am 21.11.2011 23:05, schrieb Peter Chubb:
> Hi Peter,
>    Here's a fixed patch for the sp804 timer.
> 
> Properly implement the dual-timer read/write for the sp804 dual timer module.
> Based on ARM specs at
> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
> 
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> Signed-off-by: David Mirabito <david.mirabito@nicta.com.au>
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>

Please again check and improve the commit message and SoB.

> Index: qemu-working/hw/arm_timer.c
> ===================================================================
> --- qemu-working.orig/hw/arm_timer.c	2011-11-21 09:05:05.566351984 +1100
> +++ qemu-working/hw/arm_timer.c	2011-11-21 09:05:10.582372066 +1100

> @@ -263,35 +292,35 @@ typedef struct {
>  
>  static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
>                               unsigned size)
>  {
>      icp_pit_state *s = (icp_pit_state *)opaque;
>      int n;
>  
>      /* ??? Don't know the PrimeCell ID for this device.  */
>      n = offset >> 8;
>      if (n > 2) {
> -        hw_error("sp804_read: Bad timer %d\n", n);
> +        hw_error("icp_pit_read: Bad timer %d\n", n);

__func__ would be a more permanent solution to avoid such mismatches.

>      }
>  
>      return arm_timer_read(s->timer[n], offset & 0xff);
>  }
>  
>  static void icp_pit_write(void *opaque, target_phys_addr_t offset,
>                            uint64_t value, unsigned size)
>  {
>      icp_pit_state *s = (icp_pit_state *)opaque;
>      int n;
>  
>      n = offset >> 8;
>      if (n > 2) {
> -        hw_error("sp804_write: Bad timer %d\n", n);
> +        hw_error("icp_pit_write: Bad timer %d\n", n);

Dito.

Either way these two cleanups belong in a separate patch.

Regards,
Andreas

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 22:45         ` Andreas Färber
@ 2011-11-21 23:04           ` Peter Chubb
  2011-11-21 23:10             ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-21 23:04 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Peter Maydell, Peter Chubb, Peter Chubb, qemu-devel

>>>>> "Andreas" == Andreas Färber <andreas.faerber@web.de> writes:

Andreas> Hi Peter, Am 21.11.2011 22:58, schrieb Peter Chubb:
>> Hi Peter, Please find appended a patch containing initial support
>> for the FreeScale i.MX31 and the KZM Arm11 evaluation board.

Andreas> Your patch format is a bit unusual.

Andreas> Please don't include personal messages in the description,
Andreas> keep it in a format we can apply unchanged with git-am.

OK, I'll try to fix it -- I'm using Quilt so it's not too hard.

Andreas> git-am complains:

Andreas> /home/andreas/QEMU/qemu-arm/.git/rebase-apply/patch:43: new
Andreas> blank line at EOF.  + warning: 1 line adds whitespace errors.

Dunno where that comes from.

>> The implementation was originally written by Hans Jang and Adam
>> Clench of OK-Labs; I've updated it to the current qdev and memory
>> region paradigms and implemented enough extra that Linux will boot
>> on the patched QEMU using a ram disk.
>> 
>> The i.MX 31 Serial controller is found in most of the i.MX SoCs;
>> the AVIC and timer implementations can also be shared, albeit with
>> fewer chips.
>> 
>> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
>> Signed-off-by: Hans Jang <hsjang@ok-labs.com> Signed-off-by: Adam
>> Clench <adamc@ok-labs.com>

Andreas> If as you describe above, you polished up patches originally
Andreas> by OK-Labs then your SoB should be placed last.

Will fix.

>> 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-22 08:51:09.733239638 +1100 @@
>> -0,0 +1,294 @@ +/* + * IMX31 Vectored Interrupt Controller + * + *
>> Note this is NOT the PL192 provided by ARM, but + * a custom
>> implementation by FreeScale.  + * + * Copyright (c) 2008 OKL + *
>> Written by Hans + * + * This code is licenced under the GPL.

Andreas> If you can, it would be nice to clarify the "GPL" license:

Andreas>     ... the GNU General Public License as published by the
Andreas> Free Software Foundation; either version 1, or (at your
Andreas> option) any later version.

I think it's version 2.0 or later.  I'll check and fix.

>> + * + * TODO: implement vectors and priorities.  + */ + +#include
>> "hw.h" +#include "sysbus.h" +#include <string.h> /* ffsll */ +
>> +#define DEBUG_INT 1 +#undef DEBUG_INT /* comment out for debugging
>> */

Andreas> Usually we just do //#define DEBUG_...

Checkpatch.pl complains about that!


>> ??? Save/restore.  */

Andreas> What does this comment tell us? :)

Dunno.  It was in the codebase I got; I think it means that save and
restore aren't implemented yet.

Andreas> My sharp eye also spotted an | without spaces somewhere. If
Andreas> you haven't already, try running scripts/checkpatch.pl.

I couldn't find one that was obvious, except in the big list of
reset-by-write-one bits in the imx_serial.c code:

 value &= (1<<15)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|
            (1<<8)|(1<<7)|(1<<6)|(1<<4)|(1<<2)|(1<<1);

checkpatch.pl didn't complain about this!


Thanks for reviewing.


--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 23:04           ` Peter Chubb
@ 2011-11-21 23:10             ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-21 23:10 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Andreas Färber, Peter Chubb, qemu-devel

On 21 November 2011 23:04, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>>>>>> "Andreas" == Andreas Färber <andreas.faerber@web.de> writes:

>>> ??? Save/restore.  */
>
> Andreas> What does this comment tell us? :)
>
> Dunno.  It was in the codebase I got; I think it means that save and
> restore aren't implemented yet.

I think what Andreas is trying to hint is that it means you need
to implement save/restore :-) (ditto in the interrupt controller)

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 21:58       ` [Qemu-devel] [PATCH] imx.31 and KZM board support Peter Chubb
  2011-11-21 22:45         ` Andreas Färber
@ 2011-11-21 23:41         ` Peter Maydell
  2011-11-21 23:54           ` Peter Chubb
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
  2011-11-22 11:06         ` [Qemu-devel] [PATCH] " Juan Quintela
  2 siblings, 2 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-21 23:41 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Chubb, qemu-devel

On 21 November 2011 21:58, Peter Chubb <peterc@gelato.unsw.edu.au> wrote:
> Hi Peter,
>   Please find appended a patch containing initial support for the
>   FreeScale i.MX31 and the KZM Arm11 evaluation board.
>
>   The implementation was originally written by Hans Jang and Adam
>   Clench of OK-Labs; I've updated it to the current qdev and memory
>   region paradigms and implemented enough extra that Linux will boot
>   on the patched QEMU using a ram disk.
>
>   The i.MX 31 Serial controller is found in most of the i.MX SoCs;
>   the AVIC and timer implementations can also be shared, albeit with
>   fewer chips.
>
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: Adam Clench <adamc@ok-labs.com>
> ---
>  Makefile.target |    1
>  hw/imx_avic.c   |  294 ++++++++++++++++++++++++++++++++++++++
>  hw/imx_serial.c |  260 +++++++++++++++++++++++++++++++++
>  hw/imx_timer.c  |  430 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/kzm.c        |  159 ++++++++++++++++++++
>  5 files changed, 1144 insertions(+)

This is a rather long patch. I think it would be easier to review
as a four patch series (1 patch per device plus 1 for the board model).

>  create mode 100644 hw/imx_avic.c
>  create mode 100644 hw/imx_serial.c
>  create mode 100644 hw/imx_timer.c
>  create mode 100644 hw/kzm.c
>
> Index: qemu-working/Makefile.target
> ===================================================================
> --- qemu-working.orig/Makefile.target   2011-11-22 08:40:56.380128155 +1100
> +++ qemu-working/Makefile.target        2011-11-22 08:42:26.288661513 +1100
> @@ -336,20 +336,21 @@ obj-sparc-y = sun4m.o lance.o tcx.o sun4
>  obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
>  obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
>
>  # GRLIB
>  obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
>  endif
>
>  obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
>  obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
>  obj-arm-y += versatile_pci.o
> +obj-arm-y += kzm.o imx_avic.o imx_serial.o imx_timer.o
>  obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
>  obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
>  obj-arm-y += pl061.o
>  obj-arm-y += arm-semi.o
>  obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
>  obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
>  obj-arm-y += gumstix.o
>  obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
>  obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
>                omap_gpio.o omap_intc.o omap_uart.o
> 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-22 08:51:09.733239638 +1100
> @@ -0,0 +1,294 @@
> +/*
> + * IMX31 Vectored Interrupt Controller
> + *
> + * Note this is NOT the PL192 provided by ARM, but
> + * a custom implementation by FreeScale.
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.
> + *
> + * TODO: implement vectors and priorities.
> + */
> +
> +#include "hw.h"
> +#include "sysbus.h"
> +#include <string.h> /* ffsll */
> +
> +#define DEBUG_INT 1
> +#undef DEBUG_INT /* comment out for debugging */
> +
> +#ifdef DEBUG_INT
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_int: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +
> +#define IMX_INT_NUM_IRQS 64
> +
> +/* 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 */
> +
> +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[IMX_INT_NUM_IRQS/(32/4)]; /* Priorities are 4-bits each */
> +} imx_int_state;
> +
> +static inline int imx_int_prio(imx_int_state *s, int irq)
> +{
> +    uint32_t word = irq / (32/4);
> +    uint32_t part = irq % (32/4);
> +    return 0xff & (s->prio[word] >> (4 * part));

If these are four bit fields (as suggested by the comment and the
size of the shift) why are we masking with 0xff rather than 0xf ?

Also can we avoid all this repetition of the (32/4) magic number?

> +static inline void imx_int_set_prio(imx_int_state *s, int irq, int prio)
> +{
> +    uint32_t word = irq / (32/4);
> +    uint32_t part = 4 * (irq % (32/4));
> +    uint32_t mask = ~(0xff << part);

In the previous function we put the *4 in the shift; here we're
doing it in the calculation of part. Be consistent, please.

> +    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 || likely((s->intmask & 0x1f) == 0x1f)) {

Is the use of likely() here really justified?

> +        qemu_set_irq(s->irq, !!flags);
> +        return;
> +    }
> +    /* Take interrupt if  prio lower than the value of intmask */
> +
> +    for (i = 0; i < IMX_INT_NUM_IRQS; i++) {
> +        if (flags & (1<<i)) {
> +            if (imx_int_prio(s, i) > s->intmask) {
> +                qemu_set_irq(s->irq, 1);
> +                return;
> +            }
> +        }
> +    }
> +
> +}
> +
> +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;

ULL

> +    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 */
> +    {
> +        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
> +        int i = ffsll(flags);
> +        if (i) {
> +            imx_int_set_irq(opaque, i-1, 0);
> +            return (i-1) << 16;
> +        }
> +        return 0xFFFF<<16;
> +    }
> +    case 17:/* Fast Interrupt vector and status register */
> +    {
> +        uint64_t flags = s->pending & s->enabled & s->is_fiq;
> +        int i = ffsll(flags);
> +        if (i) {
> +            imx_int_set_irq(opaque, i-1, 0);
> +            return (i-1) << 16;
> +        }
> +        return 0xFFFF<<16;
> +    }
> +    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;

0x

> +    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:
> +        printf("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;
> +        break;
> +    case 1: /* Normal Interrupt Mask Register, NIMASK */
> +        s->intmask = val;
> +        break;
> +    case 2: /* Interrupt Enable Number Register, INTENNUM */
> +        DPRINTF("enable(%d)\n", (int)val);
> +        s->enabled |= (1ULL << val);
> +        break;
> +    case 3: /* Interrupt Disable Number Register, INTDISNUM */
> +        s->enabled &= ~(1ULL << val);
> +        DPRINTF("disabled(%d)\n", (int)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: /* Interrypt Type Register High */

Interrupt

> +        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;
> +        return;
> +        /* 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:
> +        hw_error("imx_int_write: Bad offset %x\n", (int)offset);

Don't hw_error() for guest bad behaviour.

> +    }
> +    imx_int_update(s);
> +}
> +
> +static const MemoryRegionOps imx_int_ops = {
> +    .read = imx_int_read,
> +    .write = imx_int_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +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);
> +
> +    s->intmask = 0x1f;
> +    s->enabled = 0ULL;

The code setting member fields should be in a reset function.
Can't you just say "s->enabled = 0;" ?

> +    return 0;
> +}
> +
> +static void imx_int_register_devices(void)
> +{
> +    sysbus_register_dev("imx_int", sizeof(imx_int_state),
> +                        imx_int_init);

Use sysbus_register_withprop(). Provide a VMState so you get save/restore.


> +}
> +
> +device_init(imx_int_register_devices);

This macro doesn't need a trailing semicolon and mostly we don't
seem to give it one.



> +
> 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-22 08:49:36.084276219 +1100
> @@ -0,0 +1,260 @@
> +/*
> + * IMX31 UARTS
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL.
> + * 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
> + *  -- 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
> +#undef DEBUG_SERIAL /* comment out for debugging */
> +
> +#ifdef DEBUG_SERIAL
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_serial: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +typedef struct {
> +    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;
> +
> +#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_RDR        (1<<0)    /* Receiove data ready */

Receive

> +#define USR2_TXDC       (1<<3)    /* Transmission complete */
> +
> +#define UCR1_UARTEN     (1<<0)
> +#define UCR1_RRDYEN     (1<<9)
> +#define UCR1_TRDYEN     (1<<13)
> +#define UCR1_TXMPTYEN   (1<<6)
> +
> +#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 (0 == (s->ucr1 & UCR1_TXMPTYEN)) {

We don't use the 0 == foo style in qemu.

> +        flags &= ~USR1_TRDY;
> +    }
> +
> +    qemu_set_irq(s->irq, !!flags);
> +}
> +
> +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;
> +        s->usr1 &= ~USR1_RRDY;
> +        s->usr2 &= ~USR2_RDR;
> +        s->uts1 |= UTS1_RXEMPTY;
> +        imx_update(s);
> +        qemu_chr_accept_input(s->chr);
> +        return c | URXD_CHARRDY;
> +
> +    case 0x20: /* UCR1 */
> +        return s->ucr1;
> +
> +    case 0x21: /* UCR2 */
> +        return 1; /* reset complete */
> +
> +    case 0x25: /* USR1 */
> +        imx_update(s);
> +        return s->usr1;
> +
> +    case 0x26: /* USR2 */
> +        imx_update(s);
> +        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:
> +        hw_error("imx_serial_read: bad offset: 0x%x\n", (int)offset);
> +        /* Keep gcc happy: notreached */
> +        return 0;

Don't hw_error here.

> +    }
> +}
> +
> +
> +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 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 0x21: /* UCR2 */
> +    case 0x2d: /* UTS1 */
> +    case 0x22: /* UCR3 */
> +    case 0x23: /* UCR4 */
> +    case 0x24: /* UFCR */
> +    case 0x25: /* USR1 */
> +    case 0x2c: /* BIPR1 */
> +        /* TODO */
> +        break;
> +
> +    default:
> +        hw_error("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);
> +
> +    s->usr1 = USR1_TRDY;
> +    s->usr2 = USR2_TXFE | USR2_TXDC;
> +    s->ucr1 = UCR1_TRDYEN | UCR1_RRDYEN | UCR1_UARTEN;
> +    s->uts1 = UTS1_RXEMPTY;
> +    s->readbuff = 0;

Initialisation of fields => in a reset function.

> +    if (s->chr) {
> +        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
> +                              imx_event, s);
> +    }
> +    return 0;
> +    /* ??? Save/restore.  */

Implement save/restore :-)

> +}
> +
> +static void imx_serial_register_devices(void)
> +{
> +    DPRINTF("imx_serial_register_devices\n");
> +    sysbus_register_dev("imx_serial", sizeof(imx_state),
> +                        imx_serial_init);
> +}
> +
> +device_init(imx_serial_register_devices);

I'll come back and look at the timer and board later.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 23:41         ` Peter Maydell
@ 2011-11-21 23:54           ` Peter Chubb
  2011-11-22  0:12             ` Peter Maydell
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
  1 sibling, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-21 23:54 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Peter Chubb, Peter Chubb, qemu-devel

Thanks Peter,
I'll split the patches and resubmit.  It'll probably be tomorrow or Thursday.

Do you have a suggestion for an alternative to hw_error for guest bad
behaviour?  It seems to be used historically.  For emulating ARM,
causing qemu to stop isn't such a bad idea ... the guest does
something wrong and the qemu instance dies with a message.  It's not
as it that'll affect any other guests, each of which will have their
own qemu instance.

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 23:54           ` Peter Chubb
@ 2011-11-22  0:12             ` Peter Maydell
  2011-11-22  0:27               ` Peter Chubb
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2011-11-22  0:12 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Chubb, qemu-devel

On 21 November 2011 23:54, Peter Chubb <peterc@gelato.unsw.edu.au> wrote:
> Do you have a suggestion for an alternative to hw_error for guest bad
> behaviour?  It seems to be used historically.  For emulating ARM,
> causing qemu to stop isn't such a bad idea ... the guest does
> something wrong and the qemu instance dies with a message.  It's not
> as it that'll affect any other guests, each of which will have their
> own qemu instance.

The question's come up before and we don't currently have a good
API for it. Personally I prefer "silently ignore" for the moment;
hardware doesn't chatter at you about guest OS misbehaviour...

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] fix function names in error messages in arm_timer.c
  2011-11-21 23:01     ` Andreas Färber
@ 2011-11-22  0:20       ` Peter Chubb
  2011-11-22  3:20       ` [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c Peter Chubb
  2011-11-22  3:25       ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
  2 siblings, 0 replies; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  0:20 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Peter Maydell, davidm, qemu-devel, Peter Chubb, Paul Brook,
	Peter Chubb, philipo

Fix names of functions in error messages: as suggested by Andreas
Färber, use the C99 standard __func__ macro to get the correct name.
This fixes one real bug (the message used to print sp804 instead of
icp_pit), the other changes are cosmetic.

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>

---
 hw/arm_timer.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Index: qemu-working/hw/arm_timer.c
===================================================================
--- qemu-working.orig/hw/arm_timer.c	2011-11-22 10:43:02.575959499 +1100
+++ qemu-working/hw/arm_timer.c	2011-11-22 11:12:06.461275640 +1100
@@ -54,21 +54,21 @@ static uint32_t arm_timer_read(void *opa
         return ptimer_get_count(s->timer);
     case 2: /* TimerControl */
         return s->control;
     case 4: /* TimerRIS */
         return s->int_level;
     case 5: /* TimerMIS */
         if ((s->control & TIMER_CTRL_IE) == 0)
             return 0;
         return s->int_level;
     default:
-        hw_error("arm_timer_read: Bad offset %x\n", (int)offset);
+        hw_error("%s: Bad offset %x\n", __func__, (int)offset);
         return 0;
     }
 }
 
 /* Reset the timer limit after settings have changed.  */
 static void arm_timer_recalibrate(arm_timer_state *s, int reload)
 {
     uint32_t limit;
 
     if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
@@ -121,21 +121,21 @@ static void arm_timer_write(void *opaque
         }
         break;
     case 3: /* TimerIntClr */
         s->int_level = 0;
         break;
     case 6: /* TimerBGLoad */
         s->limit = value;
         arm_timer_recalibrate(s, 0);
         break;
     default:
-        hw_error("arm_timer_write: Bad offset %x\n", (int)offset);
+        hw_error("%s: Bad offset %x\n", __func__, (int)offset);
     }
     arm_timer_update(s);
 }
 
 static void arm_timer_tick(void *opaque)
 {
     arm_timer_state *s = (arm_timer_state *)opaque;
     s->int_level = 1;
     arm_timer_update(s);
 }
@@ -263,35 +263,35 @@ typedef struct {
 
 static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
                              unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
     if (n > 2) {
-        hw_error("sp804_read: Bad timer %d\n", n);
+        hw_error("%s: Bad timer %d\n", __func__, n);
     }
 
     return arm_timer_read(s->timer[n], offset & 0xff);
 }
 
 static void icp_pit_write(void *opaque, target_phys_addr_t offset,
                           uint64_t value, unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     n = offset >> 8;
     if (n > 2) {
-        hw_error("sp804_write: Bad timer %d\n", n);
+        hw_error("%s: Bad timer %d\n", __func__, n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);
 }
 
 static const MemoryRegionOps icp_pit_ops = {
     .read = icp_pit_read,
     .write = icp_pit_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-22  0:12             ` Peter Maydell
@ 2011-11-22  0:27               ` Peter Chubb
  2011-11-22  0:32                 ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  0:27 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Peter Chubb, Peter Chubb, qemu-devel

>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:

Peter> On 21 November 2011 23:54, Peter Chubb
Peter> <peterc@gelato.unsw.edu.au> wrote:
>> Do you have a suggestion for an alternative to hw_error for guest
>> bad behaviour?  It seems to be used historically.  For emulating
>> ARM, causing qemu to stop isn't such a bad idea ... the guest does
>> something wrong and the qemu instance dies with a message.  It's
>> not as it that'll affect any other guests, each of which will have
>> their own qemu instance.

Peter> The question's come up before and we don't currently have a
Peter> good API for it. Personally I prefer "silently ignore" for the
Peter> moment; hardware doesn't chatter at you about guest OS
Peter> misbehaviour...

Speaking as an OS developer I'd much prefer to have the simulator yell
at me when my code tries to write to bad registers.  That's one of the
reasons I try to use the emulator rather than the real hardware --- it
allows one to find bugs otherwise invisible.

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-22  0:27               ` Peter Chubb
@ 2011-11-22  0:32                 ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-22  0:32 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Chubb, qemu-devel

On 22 November 2011 00:27, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>>>>>> "Peter" == Peter Maydell <peter.maydell@linaro.org> writes:
>
> Peter> On 21 November 2011 23:54, Peter Chubb
> Peter> <peterc@gelato.unsw.edu.au> wrote:
>>> Do you have a suggestion for an alternative to hw_error for guest
>>> bad behaviour?  It seems to be used historically.  For emulating
>>> ARM, causing qemu to stop isn't such a bad idea ... the guest does
>>> something wrong and the qemu instance dies with a message.  It's
>>> not as it that'll affect any other guests, each of which will have
>>> their own qemu instance.
>
> Peter> The question's come up before and we don't currently have a
> Peter> good API for it. Personally I prefer "silently ignore" for the
> Peter> moment; hardware doesn't chatter at you about guest OS
> Peter> misbehaviour...
>
> Speaking as an OS developer I'd much prefer to have the simulator yell
> at me when my code tries to write to bad registers.  That's one of the
> reasons I try to use the emulator rather than the real hardware --- it
> allows one to find bugs otherwise invisible.

Yes, this is the trouble -- different audiences want different levels
of chattiness from qemu. An app developer/user basically doesn't care
if the OS is doing something slightly dubious because they have no
way to fix it anyhow. So you need a user-controllable verbosity level.
(And some OSes do dubious things at great rate, eg Linux on OMAP
deliberately touches a nonexistent register in its interrupt handler
path and if we warned every time we'd generate a huge volume of warnings.
So some kind of rate limit/"warned ten times about this already, don't
warn any more" would eb good too.)

But I think "kill qemu" is pretty definitely not the right thing
(unless the hardware bursts into flames if you access the bad
register, in which case maybe...)

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c
  2011-11-21 23:01     ` Andreas Färber
  2011-11-22  0:20       ` [Qemu-devel] [PATCH] [ARM] fix function names in error messages in arm_timer.c Peter Chubb
@ 2011-11-22  3:20       ` Peter Chubb
  2011-12-05 19:53         ` andrzej zaborowski
  2011-11-22  3:25       ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
  2 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  3:20 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Peter Maydell, davidm, qemu-devel, Peter Chubb, Paul Brook,
	Peter Chubb, philipo


Two of the calls to hw_error() in arm_timer.c contain the wrong function name.

As suggested by Andreas Färber, use the C99 standard __func__ macro to
get the correct name, instead of putting the name directly into the code.

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>

---
 hw/arm_timer.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Index: qemu-working/hw/arm_timer.c
===================================================================
--- qemu-working.orig/hw/arm_timer.c	2011-11-22 11:37:33.585457443 +1100
+++ qemu-working/hw/arm_timer.c	2011-11-22 13:10:25.510120391 +1100
@@ -54,21 +54,21 @@ static uint32_t arm_timer_read(void *opa
         return ptimer_get_count(s->timer);
     case 2: /* TimerControl */
         return s->control;
     case 4: /* TimerRIS */
         return s->int_level;
     case 5: /* TimerMIS */
         if ((s->control & TIMER_CTRL_IE) == 0)
             return 0;
         return s->int_level;
     default:
-        hw_error("arm_timer_read: Bad offset %x\n", (int)offset);
+        hw_error("%s: Bad offset %x\n", __func__, (int)offset);
         return 0;
     }
 }
 
 /* Reset the timer limit after settings have changed.  */
 static void arm_timer_recalibrate(arm_timer_state *s, int reload)
 {
     uint32_t limit;
 
     if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
@@ -121,21 +121,21 @@ static void arm_timer_write(void *opaque
         }
         break;
     case 3: /* TimerIntClr */
         s->int_level = 0;
         break;
     case 6: /* TimerBGLoad */
         s->limit = value;
         arm_timer_recalibrate(s, 0);
         break;
     default:
-        hw_error("arm_timer_write: Bad offset %x\n", (int)offset);
+        hw_error("%s: Bad offset %x\n", __func__, (int)offset);
     }
     arm_timer_update(s);
 }
 
 static void arm_timer_tick(void *opaque)
 {
     arm_timer_state *s = (arm_timer_state *)opaque;
     s->int_level = 1;
     arm_timer_update(s);
 }
@@ -263,35 +263,35 @@ typedef struct {
 
 static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
                              unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
     if (n > 2) {
-        hw_error("sp804_read: Bad timer %d\n", n);
+        hw_error("%s: Bad timer %d\n", __func__, n);
     }
 
     return arm_timer_read(s->timer[n], offset & 0xff);
 }
 
 static void icp_pit_write(void *opaque, target_phys_addr_t offset,
                           uint64_t value, unsigned size)
 {
     icp_pit_state *s = (icp_pit_state *)opaque;
     int n;
 
     n = offset >> 8;
     if (n > 2) {
-        hw_error("sp804_write: Bad timer %d\n", n);
+        hw_error("%s: Bad timer %d\n", __func__, n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);
 }
 
 static const MemoryRegionOps icp_pit_ops = {
     .read = icp_pit_read,
     .write = icp_pit_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };


--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-11-21 23:01     ` Andreas Färber
  2011-11-22  0:20       ` [Qemu-devel] [PATCH] [ARM] fix function names in error messages in arm_timer.c Peter Chubb
  2011-11-22  3:20       ` [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c Peter Chubb
@ 2011-11-22  3:25       ` Peter Chubb
  2011-11-24 17:46         ` Peter Maydell
  2 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  3:25 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Peter Maydell, davidm, qemu-devel, Peter Chubb, Paul Brook,
	Peter Chubb, philipo

Properly implement dual-timer read/write for the sp804 dual timer module.
Based on ARM specs at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html

Signed-off-by: Hans Jang <hsjang@ok-labs.com>
Signed-off-by: David Mirabito <david.mirabito@nicta.com.au>
Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>

---
 hw/arm_timer.c |   41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

Index: qemu-working/hw/arm_timer.c
===================================================================
--- qemu-working.orig/hw/arm_timer.c	2011-11-22 14:21:50.873221242 +1100
+++ qemu-working/hw/arm_timer.c	2011-11-22 14:22:21.986129734 +1100
@@ -163,64 +163,93 @@ static arm_timer_state *arm_timer_init(u
     s->freq = freq;
     s->control = TIMER_CTRL_IE;
 
     bh = qemu_bh_new(arm_timer_tick, s);
     s->timer = ptimer_init(bh);
     vmstate_register(NULL, -1, &vmstate_arm_timer, s);
     return s;
 }
 
 /* ARM PrimeCell SP804 dual timer module.
-   Docs for this device don't seem to be publicly available.  This
-   implementation is based on guesswork, the linux kernel sources and the
-   Integrator/CP timer modules.  */
+ * Docs at
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
+*/
 
 typedef struct {
     SysBusDevice busdev;
     MemoryRegion iomem;
     arm_timer_state *timer[2];
     int level[2];
     qemu_irq irq;
 } sp804_state;
 
+static const uint8_t sp804_ids[] = {
+    /* Timer ID */
+    0x04, 0x18, 0x14, 0,
+    /* PrimeCell ID */
+    0xd, 0xf0, 0x05, 0xb1
+};
+
 /* Merge the IRQs from the two component devices.  */
 static void sp804_set_irq(void *opaque, int irq, int level)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     s->level[irq] = level;
     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 }
 
 static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
                            unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
-    /* ??? Don't know the PrimeCell ID for this device.  */
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
-    } else {
+    }
+    if (offset < 0x40) {
         return arm_timer_read(s->timer[1], offset - 0x20);
     }
+
+    /* TimerPeriphID */
+    if (offset >= 0xfe0 && offset <= 0xffc) {
+        return sp804_ids[(offset - 0xfe0) >> 2];
+    }
+
+    switch (offset) {
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        return 0;
+    }
+
+    hw_error("%s: Bad offset %x\n", __func__, (int)offset);
+    return 0;
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
                         uint64_t value, unsigned size)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
-    } else {
+        return;
+    }
+
+    if (offset < 0x40) {
         arm_timer_write(s->timer[1], offset - 0x20, value);
+        return;
     }
+
+    /* Technically we could be writing to the Test Registers, but not likely */
+    hw_error("%s: Bad offset %x\n", __func__, (int)offset);
 }
 
 static const MemoryRegionOps sp804_ops = {
     .read = sp804_read,
     .write = sp804_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_sp804 = {
     .name = "sp804",

--
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] 45+ messages in thread

* [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support
  2011-11-21 23:41         ` Peter Maydell
  2011-11-21 23:54           ` Peter Chubb
@ 2011-11-22  4:31           ` Peter Chubb
  2011-11-22  4:32             ` [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support Peter Chubb
                               ` (4 more replies)
  1 sibling, 5 replies; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  4:31 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Andreas Färber, Peter Chubb, qemu-devel

Here follow four patches in separate emails, to implement basic
i.mx31 SoC support, and the KZM evaluation board built around this
chip.

The patch to the Makefile to build all the files is in the last of
the series, rather than changing Makefile.hw in each patch.

All comments received so far have been addressed --- I've added a
macro, `scream' that gives at most 10 lines of output for OS error
reporting.

Signed-off-by lines are in each individual patch.  The work was
originally done by people at OK-Labs sufficient to get OK-L4 running;
I've cleaned it up and added sufficient new functionality to get Linux
running with an initial RAM disk.
--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
@ 2011-11-22  4:32             ` Peter Chubb
  2011-11-24 18:53               ` Peter Maydell
  2011-11-22  4:33             ` [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support Peter Chubb
                               ` (3 subsequent siblings)
  4 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  4:32 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Andreas Färber, qemu-devel


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: 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>
---
 hw/imx_serial.c |  307 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 307 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-22 14:47:09.242035743 +1100
@@ -0,0 +1,307 @@
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ *
+ * 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
+ *  -- 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
+
+/*
+ * Print a message at most ten times.
+ */
+#define scream(fmt, args...) \
+    do { \
+        static int printable = 10;\
+        if (printable--) { \
+            fprintf(stderr, fmt, ##args); \
+        } \
+    } while (0)
+
+
+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_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_RDR        (1<<0)    /* Receive data ready */
+#define USR2_TXDC       (1<<3)    /* Transmission complete */
+
+#define UCR1_UARTEN     (1<<0)
+#define UCR1_RRDYEN     (1<<9)
+#define UCR1_TRDYEN     (1<<13)
+#define UCR1_TXMPTYEN   (1<<6)
+
+#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;
+    }
+
+    qemu_set_irq(s->irq, !!flags);
+}
+
+static void imx_serial_reset(imx_state *s)
+{
+    s->usr1 = USR1_TRDY;
+    s->usr2 = USR2_TXFE | USR2_TXDC;
+    s->uts1 = UTS1_RXEMPTY;
+    s->ubrm = 0;
+    s->ubrc = 0;
+    s->readbuff = 0;
+}
+
+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;
+        s->usr1 &= ~USR1_RRDY;
+        s->usr2 &= ~USR2_RDR;
+        s->uts1 |= UTS1_RXEMPTY;
+        imx_update(s);
+        qemu_chr_accept_input(s->chr);
+        return c | URXD_CHARRDY;
+
+    case 0x20: /* UCR1 */
+        return s->ucr1;
+
+    case 0x21: /* UCR2 */
+        return 1; /* reset complete */
+
+    case 0x25: /* USR1 */
+        imx_update(s);
+        return s->usr1;
+
+    case 0x26: /* USR2 */
+        imx_update(s);
+        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:
+        scream("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);
+        }
+        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:
+        scream("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);
+    imx_serial_reset(s);
+    /*
+     * enable the uart on boot, so messages from the linux decompresser
+     * are visible
+     */
+    s->ucr1 = UCR1_UARTEN;
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+                              imx_event, s);
+    }
+    vmstate_register(&dev->qdev, -1, &vmstate_imx_serial, s);
+    return 0;
+}
+
+
+static void imx_serial_register_devices(void)
+{
+    DPRINTF("imx_serial_register_devices\n");
+    sysbus_register_dev("imx_serial", sizeof(imx_state),
+                        imx_serial_init);
+}
+
+device_init(imx_serial_register_devices)

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
  2011-11-22  4:32             ` [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support Peter Chubb
@ 2011-11-22  4:33             ` Peter Chubb
  2011-11-24 17:01               ` Peter Maydell
  2011-11-24 19:06               ` Peter Maydell
  2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller Peter Chubb
                               ` (2 subsequent siblings)
  4 siblings, 2 replies; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  4:33 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Andreas Färber, qemu-devel

Implement the timers on the FreeScale i.MX31 SoC.
This is not a complete implementation, but gives enough for 
Linux to boot and run.


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>
---
 hw/imx_timer.c |  441 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 441 insertions(+)
 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-22 14:47:10.058038639 +1100
@@ -0,0 +1,441 @@
+/*
+ * IMX31 Timer
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ * Updated by Peter Chubb
+ *
+ * This code is licenced under GPL version 2 or later.
+ */
+
+#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
+
+/*
+ * Print a message at most ten times.
+ */
+#define scream(fmt, args...) \
+    do { \
+        static int printable = 10;\
+        if (printable--) { \
+            fprintf(stderr, fmt, ##args);\
+        } \
+    } while (0)
+
+
+/*
+ * 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)
+{
+    /* Update interrupts.  */
+    if ((s->cr & GPT_CR_EN)
+        && (((s->sr & GPT_SR_OF1) && (s->ir & GPT_IR_OF1IE)) ||
+            ((s->sr & GPT_SR_ROV) && (s->ir & GPT_IR_ROVIE)))) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static uint64_t imxg_timer_update_count(imxg_timer_state *s)
+{
+    uint64_t clk = qemu_get_clock_ns(vm_clock);
+
+    s->cnt = ((uint32_t)muldiv64(clk, GPT_FREQ/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));
+/*
+                   clk + muldiv64(get_ticks_per_sec(),
+                                            diff_cnt, GPT_FREQ)
+*/
+}
+
+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;
+    }
+
+    scream("imxg_timer_read: Bad offset %x\n",
+               (int)offset >> 2);
+    return 0;
+}
+
+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;
+            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;
+        }
+        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:
+        scream("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);
+    s->cr = 0;
+    s->ir = 0;
+    s->pr = 0;
+    s->ocr1 = 0;
+    imxg_timer_update_count(s);
+
+    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 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);
+    }
+    scream("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 */
+        if (s->cr & CR_EN) {
+            ptimer_run(s->timer, 0);
+        } else {
+            ptimer_stop(s->timer);
+        }
+        if (s->cr & CR_SWR) {
+            s->cr = 0;
+            s->lr = 0;
+            ptimer_stop(s->timer);
+        }
+        break;
+
+    case 1: /* SR - ACK*/
+        s->int_level = 0;
+        imxp_timer_update(s);
+        break;
+
+    case 2: /* LR - set ticks*/
+        s->lr = value;
+        ptimer_set_freq(s->timer, EPIT_FREQ);
+        ptimer_set_limit(s->timer, value, 1);
+        break;
+
+    case 3: /* CMP */
+        s->cmp = value;
+        break;
+
+    default:
+        scream("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);
+
+    s->cr = 0;
+    s->lr = 0;
+
+    bh = qemu_bh_new(imxp_timer_tick, s);
+    s->timer = ptimer_init(bh);
+    vmstate_register(&dev->qdev, -1, &vmstate_imxp_timer, s);
+
+    return 0;
+}
+
+static void imx_timer_register_devices(void)
+{
+    DPRINTF("Registering Timers\n");
+    sysbus_register_dev("imx_timerp", sizeof(imxp_timer_state),
+                        imxp_timer_init);
+    sysbus_register_dev("imx_timerg", sizeof(imxg_timer_state),
+                        imxg_timer_init);
+}
+
+
+device_init(imx_timer_register_devices);

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
  2011-11-22  4:32             ` [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support Peter Chubb
  2011-11-22  4:33             ` [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support Peter Chubb
@ 2011-11-22  4:34             ` Peter Chubb
  2011-11-24 19:37               ` Peter Maydell
  2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board Peter Chubb
  2011-11-23  0:51             ` [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support Peter Chubb
  4 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  4:34 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Andreas Färber, qemu-devel

Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least
to the extent it is used by Linux 3.0.x

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>
---
 hw/imx_avic.c |  363 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 363 insertions(+)
 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-22 14:47:10.706040936 +1100
@@ -0,0 +1,363 @@
+/*
+ * IMX31 Vectored Interrupt Controller
+ *
+ * Note this is NOT the PL192 provided by ARM, but
+ * a custom implementation by FreeScale.
+ *
+ * Copyright (c) 2008 OKL
+ * Written by Hans
+ *
+ * This code is licenced under the GPL version 2 or later.
+ *
+ * TODO: implement vectors and priorities.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include <string.h> /* ffsll */
+
+#define DEBUG_INT 1
+#undef DEBUG_INT /* comment out for debugging */
+
+#ifdef DEBUG_INT
+#define DPRINTF(fmt, args...) \
+do { printf("imx_int: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Print a message at most ten times.
+ */
+#define scream(fmt, args...) \
+    do { \
+        static int printable = 10;\
+        if (printable--) { \
+            fprintf(stderr, fmt, ##args); \
+        } \
+    } while (0)
+
+
+#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) == 0x1f)) {
+        qemu_set_irq(s->irq, !!flags);
+        return;
+    }
+
+    /* Take interrupt if  prio lower than the value of intmask */
+    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;
+            }
+        }
+    }
+
+}
+
+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 */
+    {
+        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
+        int i = ffsll(flags);
+        if (i) {
+            imx_int_set_irq(opaque, i-1, 0);
+            return (i-1) << 16;
+        }
+        return 0xFFFFULL<<16;
+    }
+    case 17:/* Fast Interrupt vector and status register */
+    {
+        uint64_t flags = s->pending & s->enabled & s->is_fiq;
+        int i = ffsll(flags);
+        if (i) {
+            imx_int_set_irq(opaque, i-1, 0);
+            return (i-1) << 16;
+        }
+        return 0xFFFF<<16;
+    }
+    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:
+        scream("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;
+        break;
+
+    case 1: /* Normal Interrupt Mask Register, NIMASK */
+        s->intmask = val;
+        break;
+
+    case 2: /* Interrupt Enable Number Register, INTENNUM */
+        DPRINTF("enable(%d)\n", (int)val);
+        s->enabled |= (1ULL << val);
+        break;
+
+    case 3: /* Interrupt Disable Number Register, INTDISNUM */
+        s->enabled &= ~(1ULL << val);
+        DPRINTF("disabled(%d)\n", (int)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;
+        return;
+
+        /* 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:
+        scream("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(imx_int_state *s)
+{
+    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);
+
+    imx_int_reset(s);
+
+    vmstate_register(&dev->qdev, -1, &vmstate_imx_avic, s);
+    return 0;
+}
+
+static void imx_int_register_devices(void)
+{
+    SysBusDeviceInfo *info = g_malloc0(sizeof *info);
+    info->qdev.name = "imx_int";
+    info->qdev.desc = "i.MX Advanced Vector Interrupt Controller";
+    info->qdev.size = sizeof(imx_int_state);
+    info->init = imx_int_init;
+    sysbus_register_withprop(info);
+}
+
+device_init(imx_int_register_devices)
+

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
                               ` (2 preceding siblings ...)
  2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller Peter Chubb
@ 2011-11-22  4:34             ` Peter Chubb
  2011-11-24 19:41               ` Peter Maydell
  2011-11-23  0:51             ` [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support Peter Chubb
  4 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-22  4:34 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Andreas Färber, qemu-devel

Board support for Kyoto Micro's KZM-ARM11-01, an evaluation board built
around the FreeScale i.MX31.

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/kzm.c        |  155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 157 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-22 14:47:11.358042471 +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-22 14:46:58.313978625 +1100
+++ qemu-working/Makefile.target	2011-11-22 14:47:11.358042471 +1100
@@ -361,20 +361,22 @@ 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 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
 

--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-21 21:58       ` [Qemu-devel] [PATCH] imx.31 and KZM board support Peter Chubb
  2011-11-21 22:45         ` Andreas Färber
  2011-11-21 23:41         ` Peter Maydell
@ 2011-11-22 11:06         ` Juan Quintela
  2011-11-22 11:14           ` Peter Maydell
  2011-11-23  0:48           ` Peter Chubb
  2 siblings, 2 replies; 45+ messages in thread
From: Juan Quintela @ 2011-11-22 11:06 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Peter Chubb, qemu-devel

Peter Chubb <peterc@gelato.unsw.edu.au> wrote:
> Hi Peter,
>    Please find appended a patch containing initial support for the
>    FreeScale i.MX31 and the KZM Arm11 evaluation board.
>
>    The implementation was originally written by Hans Jang and Adam
>    Clench of OK-Labs; I've updated it to the current qdev and memory
>    region paradigms and implemented enough extra that Linux will boot
>    on the patched QEMU using a ram disk.
>
>    The i.MX 31 Serial controller is found in most of the i.MX SoCs;
>    the AVIC and timer implementations can also be shared, albeit with
>    fewer chips.
>
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: Adam Clench <adamc@ok-labs.com>

> +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()
> +    }
> +};

This is not used.  Shouldn't a call like this be needed?

> +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);
> +    s->cr = 0;
> +    s->ir = 0;
> +    s->pr = 0;
> +    s->ocr1 = 0;
> +    imxg_timer_update_count(s);

       vmstate_register(&dev->qdev, -1, &vmstate_imxg_timer, s);
???


I only looked at the vmstate bits, though.

Later, Juan.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-22 11:06         ` [Qemu-devel] [PATCH] " Juan Quintela
@ 2011-11-22 11:14           ` Peter Maydell
  2011-11-23 14:24             ` Juan Quintela
  2011-11-23  0:48           ` Peter Chubb
  1 sibling, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2011-11-22 11:14 UTC (permalink / raw)
  To: quintela; +Cc: Peter Chubb, Peter Chubb, qemu-devel

On 22 November 2011 11:06, Juan Quintela <quintela@redhat.com> wrote:
> Peter Chubb <peterc@gelato.unsw.edu.au> wrote:
>> Hi Peter,
>>    Please find appended a patch containing initial support for the
>>    FreeScale i.MX31 and the KZM Arm11 evaluation board.
>>
>>    The implementation was originally written by Hans Jang and Adam
>>    Clench of OK-Labs; I've updated it to the current qdev and memory
>>    region paradigms and implemented enough extra that Linux will boot
>>    on the patched QEMU using a ram disk.
>>
>>    The i.MX 31 Serial controller is found in most of the i.MX SoCs;
>>    the AVIC and timer implementations can also be shared, albeit with
>>    fewer chips.
>>
>> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
>> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
>> Signed-off-by: Adam Clench <adamc@ok-labs.com>
>
>> +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()
>> +    }
>> +};
>
> This is not used.  Shouldn't a call like this be needed?
>
>> +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);
>> +    s->cr = 0;
>> +    s->ir = 0;
>> +    s->pr = 0;
>> +    s->ocr1 = 0;
>> +    imxg_timer_update_count(s);
>
>       vmstate_register(&dev->qdev, -1, &vmstate_imxg_timer, s);
> ???

Any particular reason to prefer a vmstate_register() call
over just having a SysBusDeviceInfo struct with the .qdev.vmsd
field set? I tend to prefer the latter myself.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-22 11:06         ` [Qemu-devel] [PATCH] " Juan Quintela
  2011-11-22 11:14           ` Peter Maydell
@ 2011-11-23  0:48           ` Peter Chubb
  1 sibling, 0 replies; 45+ messages in thread
From: Peter Chubb @ 2011-11-23  0:48 UTC (permalink / raw)
  To: quintela; +Cc: Peter Maydell, Peter Chubb, Peter Chubb, qemu-devel

>>>>> "Juan" == Juan Quintela <quintela@redhat.com> writes:

Juan> Peter Chubb <peterc@gelato.unsw.edu.au> wrote:
Juan> This is not used.  Shouldn't a call like this be needed?


Juan>        vmstate_register(&dev->qdev, -1, &vmstate_imxg_timer, s);
Juan> ???

Yes!! Thanks for checking.

I've altered the source ready for the next rollout of patches, which
will be version 3.
--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support
  2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
                               ` (3 preceding siblings ...)
  2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board Peter Chubb
@ 2011-11-23  0:51             ` Peter Chubb
  2011-11-24 19:07               ` Andreas Färber
  4 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-23  0:51 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Andreas Färber, qemu-devel

>>>>> "Peter" == Peter Chubb <peter.chubb@nicta.com.au> writes:


Peter> All comments received so far have been addressed --- I've added
Peter> a macro, `scream' that gives at most 10 lines of output for OS
Peter> error reporting.

Except I noticed a thinko in the macro.  The decrement should be
inside the guard, thus:

#define scream(fmt, args...) \
    do { \
        static int printable = 10;\
        if (printable) { \
            printable--;\
            fprintf(stderr, fmt, ##args); \
        } \
    } while (0)


--
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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] imx.31 and KZM board support
  2011-11-22 11:14           ` Peter Maydell
@ 2011-11-23 14:24             ` Juan Quintela
  0 siblings, 0 replies; 45+ messages in thread
From: Juan Quintela @ 2011-11-23 14:24 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Peter Chubb, Peter Chubb, qemu-devel

Peter Maydell <peter.maydell@linaro.org> wrote:
> On 22 November 2011 11:06, Juan Quintela <quintela@redhat.com> wrote:
>> Peter Chubb <peterc@gelato.unsw.edu.au> wrote:

>>
>>       vmstate_register(&dev->qdev, -1, &vmstate_imxg_timer, s);
>> ???
>
> Any particular reason to prefer a vmstate_register() call
> over just having a SysBusDeviceInfo struct with the .qdev.vmsd
> field set? I tend to prefer the latter myself.

I didn't saw a .qdev to hijack into on the patch O:-)
I also preffer to put it inside .qdev, we get
registration/unregistration working for free.

Later, Juan.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support
  2011-11-22  4:33             ` [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support Peter Chubb
@ 2011-11-24 17:01               ` Peter Maydell
  2011-11-24 19:06               ` Peter Maydell
  1 sibling, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 17:01 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Andreas Färber, qemu-devel

On 22 November 2011 04:33, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> +/*
> + * Print a message at most ten times.
> + */
> +#define scream(fmt, args...) \
> +    do { \
> +        static int printable = 10;\
> +        if (printable--) { \
> +            fprintf(stderr, fmt, ##args);\
> +        } \
> +    } while (0)

Sorry, when I was talking about rate limits and things I didn't
mean that we should add them in individual device models but that
we needed a logging/warning infrastructure that included them.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer
  2011-11-22  3:25       ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
@ 2011-11-24 17:46         ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 17:46 UTC (permalink / raw)
  To: Peter Chubb
  Cc: davidm, qemu-devel, Andreas Färber, Paul Brook, Peter Chubb,
	philipo

On 22 November 2011 03:25, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Properly implement dual-timer read/write for the sp804 dual timer module.
> Based on ARM specs at
> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
>
> Signed-off-by: Hans Jang <hsjang@ok-labs.com>
> Signed-off-by: David Mirabito <david.mirabito@nicta.com.au>
> Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>

I'm not hugely happy about the hw_error()s but it's not making the
problem worse and we don't really have anything better to use
instead, so I'll let that pass.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

(and put into my arm-devs.next queue)

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support
  2011-11-22  4:32             ` [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support Peter Chubb
@ 2011-11-24 18:53               ` Peter Maydell
  2011-11-24 22:18                 ` Peter Chubb
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 18:53 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Andreas Färber, qemu-devel

On 22 November 2011 04:32, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>
> 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: 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>
> ---
>  hw/imx_serial.c |  307 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 307 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-22 14:47:09.242035743 +1100
> @@ -0,0 +1,307 @@
> +/*
> + * IMX31 UARTS
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.

Really v2 only? (you will need an ack from the copyright holder to say
'2 or later' here, though).

> + * 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

I assume readbuff is currently standing in as a single word fifo?
Might be worth a comment. (You'll break save/restore compatibility
when you add the fifos properly but I don't think we need to worry
about that.)

> + *  -- 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
> +
> +/*
> + * Print a message at most ten times.
> + */
> +#define scream(fmt, args...) \
> +    do { \
> +        static int printable = 10;\
> +        if (printable--) { \
> +            fprintf(stderr, fmt, ##args); \
> +        } \
> +    } while (0)

Drop this.

> +
> +
> +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 []) {

checkpatch complains about this space before the [].

> +        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()

This list seems to be missing readbuff.

> +    },
> +};
> +
> +
> +#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_RDR        (1<<0)    /* Receive data ready */
> +#define USR2_TXDC       (1<<3)    /* Transmission complete */
> +
> +#define UCR1_UARTEN     (1<<0)
> +#define UCR1_RRDYEN     (1<<9)
> +#define UCR1_TRDYEN     (1<<13)
> +#define UCR1_TXMPTYEN   (1<<6)

Is there any significance to the order of these?

> +#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;
> +    }
> +
> +    qemu_set_irq(s->irq, !!flags);
> +}
> +
> +static void imx_serial_reset(imx_state *s)
> +{
> +    s->usr1 = USR1_TRDY;
> +    s->usr2 = USR2_TXFE | USR2_TXDC;
> +    s->uts1 = UTS1_RXEMPTY;
> +    s->ubrm = 0;
> +    s->ubrc = 0;
> +    s->readbuff = 0;
> +}
> +
> +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;
> +        s->usr1 &= ~USR1_RRDY;
> +        s->usr2 &= ~USR2_RDR;
> +        s->uts1 |= UTS1_RXEMPTY;
> +        imx_update(s);
> +        qemu_chr_accept_input(s->chr);
> +        return c | URXD_CHARRDY;
> +
> +    case 0x20: /* UCR1 */
> +        return s->ucr1;
> +
> +    case 0x21: /* UCR2 */
> +        return 1; /* reset complete */
> +
> +    case 0x25: /* USR1 */
> +        imx_update(s);
> +        return s->usr1;

Why do we need to call imx_update() in the read function?
Surely it should be called only where we update the registers
which affect interrupt status?

> +
> +    case 0x26: /* USR2 */
> +        imx_update(s);
> +        return s->usr2;
> +
> +

Stray blank line. (There are a few of these in the file.)

> +    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:
> +        scream("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);
> +        }
> +        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:
> +        scream("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);
> +    imx_serial_reset(s);

If you put imx_serial_reset in a SysBusDeviceInfo struct as the
.qdev.reset pointer you don't need to call it from your init function.

> +    /*
> +     * enable the uart on boot, so messages from the linux decompresser
> +     * are visible
> +     */
> +    s->ucr1 = UCR1_UARTEN;

Is this matching the hardware's behaviour on cold boot vs warm
boot, or is it just a random hack?

> +    if (s->chr) {
> +        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
> +                              imx_event, s);
> +    }
> +    vmstate_register(&dev->qdev, -1, &vmstate_imx_serial, s);

Put this in SysBusDeviceInfo .qdev.vmsd, don't call vmstate_register().

> +    return 0;
> +}
> +
> +
> +static void imx_serial_register_devices(void)
> +{
> +    DPRINTF("imx_serial_register_devices\n");
> +    sysbus_register_dev("imx_serial", sizeof(imx_state),
> +                        imx_serial_init);

Use sysbus_register_withprop() so you can pass it a SysBusDeviceInfo.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support
  2011-11-22  4:33             ` [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support Peter Chubb
  2011-11-24 17:01               ` Peter Maydell
@ 2011-11-24 19:06               ` Peter Maydell
  1 sibling, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 19:06 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Andreas Färber, qemu-devel

On 22 November 2011 04:33, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Implement the timers on the FreeScale i.MX31 SoC.
> This is not a complete implementation, but gives enough for
> Linux to boot and run.
>
>
> 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>
> ---
>  hw/imx_timer.c |  441 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 441 insertions(+)
>  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-22 14:47:10.058038639 +1100
> @@ -0,0 +1,441 @@
> +/*
> + * IMX31 Timer
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + * Updated by Peter Chubb
> + *
> + * This code is licenced under GPL version 2 or later.
> + */
> +
> +#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
> +
> +/*
> + * Print a message at most ten times.
> + */
> +#define scream(fmt, args...) \
> +    do { \
> +        static int printable = 10;\
> +        if (printable--) { \
> +            fprintf(stderr, fmt, ##args);\
> +        } \
> +    } while (0)
> +
> +
> +/*
> + * 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 = {

We don't seem to actually use this struct anywhere...

> +    .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),

Looks like there are missing fields here.

> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +
> +/* Check all active timers, and schedule the next timer interrupt.  */
> +static void imxg_timer_update(imxg_timer_state *s)
> +{
> +    /* Update interrupts.  */
> +    if ((s->cr & GPT_CR_EN)
> +        && (((s->sr & GPT_SR_OF1) && (s->ir & GPT_IR_OF1IE)) ||
> +            ((s->sr & GPT_SR_ROV) && (s->ir & GPT_IR_ROVIE)))) {

The registers have obviously been laid out to let you AND them
together and look for set bits so I think that would be clearer.

> +        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;

Does the hardware really do the equivalent of "% 0xffffffff" ?
That looks kind of odd.

> +    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));
> +/*
> +                   clk + muldiv64(get_ticks_per_sec(),
> +                                            diff_cnt, GPT_FREQ)
> +*/

What's this commented out code doing here?

I haven't looked much at the qemu timer infrastructure, but have
you checked whether the ptimer.c functions would be useful 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;
> +    }
> +
> +    scream("imxg_timer_read: Bad offset %x\n",
> +               (int)offset >> 2);
> +    return 0;
> +}
> +
> +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;
> +            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;
> +        }

This should probably be calling a reset function rather than
being open-coded.

> +        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:
> +        scream("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);
> +    s->cr = 0;
> +    s->ir = 0;
> +    s->pr = 0;
> +    s->ocr1 = 0;

Reset function.

> +    imxg_timer_update_count(s);
> +
> +    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;

hey, this one uses ptimers...

> +    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 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);
> +    }
> +    scream("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 */
> +        if (s->cr & CR_EN) {
> +            ptimer_run(s->timer, 0);
> +        } else {
> +            ptimer_stop(s->timer);
> +        }
> +        if (s->cr & CR_SWR) {
> +            s->cr = 0;
> +            s->lr = 0;
> +            ptimer_stop(s->timer);
> +        }
> +        break;
> +
> +    case 1: /* SR - ACK*/
> +        s->int_level = 0;
> +        imxp_timer_update(s);
> +        break;
> +
> +    case 2: /* LR - set ticks*/
> +        s->lr = value;
> +        ptimer_set_freq(s->timer, EPIT_FREQ);
> +        ptimer_set_limit(s->timer, value, 1);
> +        break;
> +
> +    case 3: /* CMP */
> +        s->cmp = value;
> +        break;
> +
> +    default:
> +        scream("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);
> +
> +    s->cr = 0;
> +    s->lr = 0;

Reset function.

> +
> +    bh = qemu_bh_new(imxp_timer_tick, s);
> +    s->timer = ptimer_init(bh);
> +    vmstate_register(&dev->qdev, -1, &vmstate_imxp_timer, s);

SysBusDeviceInfo struct.

> +
> +    return 0;
> +}
> +
> +static void imx_timer_register_devices(void)
> +{
> +    DPRINTF("Registering Timers\n");
> +    sysbus_register_dev("imx_timerp", sizeof(imxp_timer_state),
> +                        imxp_timer_init);
> +    sysbus_register_dev("imx_timerg", sizeof(imxg_timer_state),
> +                        imxg_timer_init);
> +}
> +
> +
> +device_init(imx_timer_register_devices);

Unnecessary semicolon.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support
  2011-11-23  0:51             ` [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support Peter Chubb
@ 2011-11-24 19:07               ` Andreas Färber
  2011-11-26  5:21                 ` Peter Chubb
  0 siblings, 1 reply; 45+ messages in thread
From: Andreas Färber @ 2011-11-24 19:07 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Peter Maydell, Andreas Färber, qemu-devel

Am 23.11.2011 01:51, schrieb Peter Chubb:
>>>>>> "Peter" == Peter Chubb <peter.chubb@nicta.com.au> writes:
> 
> 
> Peter> All comments received so far have been addressed --- I've added
> Peter> a macro, `scream' that gives at most 10 lines of output for OS
> Peter> error reporting.
> 
> Except I noticed a thinko in the macro.  The decrement should be
> inside the guard, thus:
> 
> #define scream(fmt, args...) \
>     do { \
>         static int printable = 10;\
>         if (printable) { \
>             printable--;\
>             fprintf(stderr, fmt, ##args); \
>         } \
>     } while (0)

Another issue:

scream("black");
scream("black");
scream("black");
scream("black");
scream("black");
scream("black");
scream("black");
scream("black");
scream("black");
scream("black");
scream("red");

To show us "red", in addition to the integer count a duplicate of the
string contents would need to be stored and compared to the newly
formatted string.

If we want to do this, it should go into a central file so that it can
be reused and centrally maintained.

Andreas

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller
  2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller Peter Chubb
@ 2011-11-24 19:37               ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 19:37 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Andreas Färber, qemu-devel

On 22 November 2011 04:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Implement the FreeSCALE i.MX31 advanced vectored interrupt controller, at least
> to the extent it is used by Linux 3.0.x
>
> 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>
> ---
>  hw/imx_avic.c |  363 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 363 insertions(+)
>  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-22 14:47:10.706040936 +1100
> @@ -0,0 +1,363 @@
> +/*
> + * IMX31 Vectored Interrupt Controller
> + *
> + * Note this is NOT the PL192 provided by ARM, but
> + * a custom implementation by FreeScale.
> + *
> + * Copyright (c) 2008 OKL
> + * Written by Hans
> + *
> + * This code is licenced under the GPL version 2 or later.
> + *
> + * TODO: implement vectors and priorities.
> + */
> +
> +#include "hw.h"
> +#include "sysbus.h"
> +#include <string.h> /* ffsll */

ffsll is a glibc extension. Use ctz64() from host-utils.h
instead (but check that the edge case of no bits set is
handled the way you need, the semantics aren't identical.)

> +
> +#define DEBUG_INT 1
> +#undef DEBUG_INT /* comment out for debugging */
> +
> +#ifdef DEBUG_INT
> +#define DPRINTF(fmt, args...) \
> +do { printf("imx_int: " fmt , ##args); } while (0)
> +#else
> +#define DPRINTF(fmt, args...) do {} while (0)
> +#endif
> +
> +/*
> + * Print a message at most ten times.
> + */
> +#define scream(fmt, args...) \
> +    do { \
> +        static int printable = 10;\
> +        if (printable--) { \
> +            fprintf(stderr, fmt, ##args); \
> +        } \
> +    } while (0)
> +
> +
> +#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;
> +}

We don't seem to ever call this function?

> +/* 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) == 0x1f)) {

This &0x1f is only needed because you're incorrectly allowing
the high bits of the register to get set (see below).

> +        qemu_set_irq(s->irq, !!flags);
> +        return;
> +    }
> +
> +    /* Take interrupt if  prio lower than the value of intmask */

stray space.

> +    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;
> +            }
> +        }
> +    }

Should we be deasserting the irq line if none of the pending
interrupts have sufficient priority?

> +
> +}
> +
> +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 */
> +    {
> +        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
> +        int i = ffsll(flags);
> +        if (i) {
> +            imx_int_set_irq(opaque, i-1, 0);
> +            return (i-1) << 16;
> +        }
> +        return 0xFFFFULL<<16;
> +    }
> +    case 17:/* Fast Interrupt vector and status register */
> +    {
> +        uint64_t flags = s->pending & s->enabled & s->is_fiq;
> +        int i = ffsll(flags);
> +        if (i) {
> +            imx_int_set_irq(opaque, i-1, 0);
> +            return (i-1) << 16;
> +        }
> +        return 0xFFFF<<16;

Why ULL in the previous cases and not this one?

> +    }
> +    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:
> +        scream("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;
> +        break;
> +
> +    case 1: /* Normal Interrupt Mask Register, NIMASK */
> +        s->intmask = val;

The manual I have documents this register as only having five
significant bits, with the upper bits all being reads-as-zero,
writes-ignored. This implements them as being read-write.
(Please check the other registers to see if they have similar bugs.)

> +        break;
> +
> +    case 2: /* Interrupt Enable Number Register, INTENNUM */
> +        DPRINTF("enable(%d)\n", (int)val);
> +        s->enabled |= (1ULL << val);
> +        break;
> +
> +    case 3: /* Interrupt Disable Number Register, INTDISNUM */
> +        s->enabled &= ~(1ULL << val);
> +        DPRINTF("disabled(%d)\n", (int)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;
> +        return;
> +
> +        /* 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:
> +        scream("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(imx_int_state *s)
> +{
> +    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);
> +
> +    imx_int_reset(s);
> +
> +    vmstate_register(&dev->qdev, -1, &vmstate_imx_avic, s);

Use a SysBusDeviceInfo struct and set .qdev.vmsd.

> +    return 0;
> +}
> +
> +static void imx_int_register_devices(void)
> +{
> +    SysBusDeviceInfo *info = g_malloc0(sizeof *info);
> +    info->qdev.name = "imx_int";
> +    info->qdev.desc = "i.MX Advanced Vector Interrupt Controller";
> +    info->qdev.size = sizeof(imx_int_state);
> +    info->init = imx_int_init;

No, this should be a static struct. See hw/pl190.c for a random example.

> +    sysbus_register_withprop(info);
> +}
> +
> +device_init(imx_int_register_devices)

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board
  2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board Peter Chubb
@ 2011-11-24 19:41               ` Peter Maydell
  2011-11-24 20:19                 ` Andreas Färber
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 19:41 UTC (permalink / raw)
  To: Peter Chubb; +Cc: Andreas Färber, qemu-devel

On 22 November 2011 04:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Board support for Kyoto Micro's KZM-ARM11-01, an evaluation board built
> around the FreeScale i.MX31.

This patch mostly looks OK to me.

> +obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
> +obj-arm-y += kzm.o

It would be better to add the devices to the makefile in their
corresponding patches, I think. (Don't feel too strongly about that
though so somebody might overrule me.)

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board
  2011-11-24 19:41               ` Peter Maydell
@ 2011-11-24 20:19                 ` Andreas Färber
  2011-11-24 21:31                   ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Andreas Färber @ 2011-11-24 20:19 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Peter Chubb, qemu-devel

Am 24.11.2011 20:41, schrieb Peter Maydell:
> On 22 November 2011 04:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>> +obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
>> +obj-arm-y += kzm.o
> 
> It would be better to add the devices to the makefile in their
> corresponding patches, I think. (Don't feel too strongly about that
> though so somebody might overrule me.)

Well, I do: Without adding them to the Makefile they don't get
compile-tested. (I prefer convincing over ruling though.)

Andreas

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board
  2011-11-24 20:19                 ` Andreas Färber
@ 2011-11-24 21:31                   ` Peter Maydell
  2011-11-24 21:46                     ` Andreas Färber
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 21:31 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Peter Chubb, qemu-devel

On 24 November 2011 20:19, Andreas Färber <afaerber@suse.de> wrote:
> Am 24.11.2011 20:41, schrieb Peter Maydell:
>> On 22 November 2011 04:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>>> +obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
>>> +obj-arm-y += kzm.o
>>
>> It would be better to add the devices to the makefile in their
>> corresponding patches, I think. (Don't feel too strongly about that
>> though so somebody might overrule me.)
>
> Well, I do: Without adding them to the Makefile they don't get
> compile-tested. (I prefer convincing over ruling though.)

Er, which way are you arguing? If patch 1 adds hw/foo.c and also
adds foo.o to the makefile rune then it gets compile tested...

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board
  2011-11-24 21:31                   ` Peter Maydell
@ 2011-11-24 21:46                     ` Andreas Färber
  2011-11-24 21:52                       ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Andreas Färber @ 2011-11-24 21:46 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Peter Chubb, qemu-devel

Am 24.11.2011 22:31, schrieb Peter Maydell:
> On 24 November 2011 20:19, Andreas Färber <afaerber@suse.de> wrote:
>> Am 24.11.2011 20:41, schrieb Peter Maydell:
>>> On 22 November 2011 04:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>>>> +obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
>>>> +obj-arm-y += kzm.o
>>>
>>> It would be better to add the devices to the makefile in their
>>> corresponding patches, I think. (Don't feel too strongly about that
>>> though so somebody might overrule me.)
>>
>> Well, I do: Without adding them to the Makefile they don't get
>> compile-tested. (I prefer convincing over ruling though.)
> 
> Er, which way are you arguing? If patch 1 adds hw/foo.c and also
> adds foo.o to the makefile rune then it gets compile tested...

I'm asking for Peter C. to revise the series, please.

Andreas

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board
  2011-11-24 21:46                     ` Andreas Färber
@ 2011-11-24 21:52                       ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-24 21:52 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Peter Chubb, qemu-devel

On 24 November 2011 21:46, Andreas Färber <afaerber@suse.de> wrote:
> Am 24.11.2011 22:31, schrieb Peter Maydell:
>> On 24 November 2011 20:19, Andreas Färber <afaerber@suse.de> wrote:
>>> Am 24.11.2011 20:41, schrieb Peter Maydell:
>>>> On 22 November 2011 04:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
>>>>> +obj-arm-y += imx_serial.o imx_timer.o imx_avic.o
>>>>> +obj-arm-y += kzm.o
>>>>
>>>> It would be better to add the devices to the makefile in their
>>>> corresponding patches, I think. (Don't feel too strongly about that
>>>> though so somebody might overrule me.)
>>>
>>> Well, I do: Without adding them to the Makefile they don't get
>>> compile-tested. (I prefer convincing over ruling though.)
>>
>> Er, which way are you arguing? If patch 1 adds hw/foo.c and also
>> adds foo.o to the makefile rune then it gets compile tested...
>
> I'm asking for Peter C. to revise the series, please.

OK, in that case we agree.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support
  2011-11-24 18:53               ` Peter Maydell
@ 2011-11-24 22:18                 ` Peter Chubb
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Chubb @ 2011-11-24 22:18 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Andreas Färber, Peter Chubb, qemu-devel

Thanks Peter,
       I've fixed the problems you noted, and have asked the OK-Labs
       folks about Licencing.  When I hear back from them I'll roll a
       new patchset --- I don't expect `GPL v2 or later' to be a
       problem.

       -- 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] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support
  2011-11-24 19:07               ` Andreas Färber
@ 2011-11-26  5:21                 ` Peter Chubb
  2011-11-26 19:35                   ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Chubb @ 2011-11-26  5:21 UTC (permalink / raw)
  To: Andreas Färber
  Cc: Peter Maydell, Andreas Färber, Peter Chubb, qemu-devel

>>>>> "Andreas" == Andreas Färber <afaerber@suse.de> writes:

Andreas> Am 23.11.2011 01:51, schrieb Peter Chubb:
>>>>>>> "Peter" == Peter Chubb <peter.chubb@nicta.com.au> writes:
>> 
>> 
Peter> All comments received so far have been addressed --- I've added
Peter> a macro, `scream' that gives at most 10 lines of output for OS
Peter> error reporting.
>> 
>> Except I noticed a thinko in the macro.  The decrement should be
>> inside the guard, thus:
>> 
>> #define scream(fmt, args...) \ do { \ static int printable = 10;\
>> if (printable) { \ printable--;\ fprintf(stderr, fmt, ##args); \ }
>> \ } while (0)

Andreas> Another issue:

Andreas> scream("black"); scream("black"); scream("black");
Andreas> scream("black"); scream("black"); scream("black");
Andreas> scream("black"); scream("black"); scream("black");
Andreas> scream("black"); scream("red");

Andreas> To show us "red", in addition to the integer count a
Andreas> duplicate of the string contents would need to be stored and
Andreas> compared to the newly formatted string.

No, because it's a macro.  Each time it appears the static count is
instantiated--- so there's a count for each call site.

Andreas> If we want to do this, it should go into a central file so
Andreas> that it can be reused and centrally maintained.

Agree -- but do we want to do this?

For this patch series, Peter M says to just use hw_error() (even
though he really doesn't like it).

Peter C

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support
  2011-11-26  5:21                 ` Peter Chubb
@ 2011-11-26 19:35                   ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2011-11-26 19:35 UTC (permalink / raw)
  To: Peter Chubb
  Cc: Andreas Färber, Peter Chubb, Andreas Färber, qemu-devel

On 26 November 2011 05:21, Peter Chubb <peterc@gelato.unsw.edu.au> wrote:
> For this patch series, Peter M says to just use hw_error() (even
> though he really doesn't like it).

No, that was about the sp804 patch, which is just tweaking an existing
device. These are new devices.

Perhaps just having a second macro like DPRINTF [ie print to stderr,
don't kill qemu] but for guest-errors would be ok. Then we could convert
those to a general 'report guest bug' interface if/when we have one.

-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c
  2011-11-22  3:20       ` [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c Peter Chubb
@ 2011-12-05 19:53         ` andrzej zaborowski
  0 siblings, 0 replies; 45+ messages in thread
From: andrzej zaborowski @ 2011-12-05 19:53 UTC (permalink / raw)
  To: Peter Chubb
  Cc: Peter Maydell, davidm, qemu-devel, Andreas Färber,
	Paul Brook, Peter Chubb, philipo

On 22 November 2011 04:20, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> Two of the calls to hw_error() in arm_timer.c contain the wrong function name.
>
> As suggested by Andreas Färber, use the C99 standard __func__ macro to
> get the correct name, instead of putting the name directly into the code.

Thanks, applied.

Cheers

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2011-12-05 19:53 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-29  2:34 [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
2011-09-29  9:58 ` Peter Maydell
2011-09-30  0:20   ` Peter Chubb
2011-09-30  9:04     ` Peter Maydell
2011-09-30  9:23       ` Peter Chubb
2011-09-30 10:07         ` Peter Maydell
     [not found]   ` <w4y5x6g8gk.wl%peter@chubb.wattle.id.au>
     [not found]     ` <CAFEAcA8-iByH0xgjkMUo3hvkrLc8NV-Lq4GbHU-d7UoF8GSX-Q@mail.gmail.com>
2011-11-21 21:58       ` [Qemu-devel] [PATCH] imx.31 and KZM board support Peter Chubb
2011-11-21 22:45         ` Andreas Färber
2011-11-21 23:04           ` Peter Chubb
2011-11-21 23:10             ` Peter Maydell
2011-11-21 23:41         ` Peter Maydell
2011-11-21 23:54           ` Peter Chubb
2011-11-22  0:12             ` Peter Maydell
2011-11-22  0:27               ` Peter Chubb
2011-11-22  0:32                 ` Peter Maydell
2011-11-22  4:31           ` [Qemu-devel] [PATCH V2 0/4] " Peter Chubb
2011-11-22  4:32             ` [Qemu-devel] [PATCH V2 1/4] imx.31 and KZM board support: UART support Peter Chubb
2011-11-24 18:53               ` Peter Maydell
2011-11-24 22:18                 ` Peter Chubb
2011-11-22  4:33             ` [Qemu-devel] [PATCH V2 2/4] imx.31 and KZM board support: Timer support Peter Chubb
2011-11-24 17:01               ` Peter Maydell
2011-11-24 19:06               ` Peter Maydell
2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 3/4] imx.31 and KZM board support: interrupt controller Peter Chubb
2011-11-24 19:37               ` Peter Maydell
2011-11-22  4:34             ` [Qemu-devel] [PATCH V2 4/4] imx.31 and KZM board support: Makefile and board Peter Chubb
2011-11-24 19:41               ` Peter Maydell
2011-11-24 20:19                 ` Andreas Färber
2011-11-24 21:31                   ` Peter Maydell
2011-11-24 21:46                     ` Andreas Färber
2011-11-24 21:52                       ` Peter Maydell
2011-11-23  0:51             ` [Qemu-devel] [PATCH V2 0/4] imx.31 and KZM board support Peter Chubb
2011-11-24 19:07               ` Andreas Färber
2011-11-26  5:21                 ` Peter Chubb
2011-11-26 19:35                   ` Peter Maydell
2011-11-22 11:06         ` [Qemu-devel] [PATCH] " Juan Quintela
2011-11-22 11:14           ` Peter Maydell
2011-11-23 14:24             ` Juan Quintela
2011-11-23  0:48           ` Peter Chubb
2011-11-21 22:05   ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
2011-11-21 23:01     ` Andreas Färber
2011-11-22  0:20       ` [Qemu-devel] [PATCH] [ARM] fix function names in error messages in arm_timer.c Peter Chubb
2011-11-22  3:20       ` [Qemu-devel] [PATCH] [ARM] Fix hw_error messages from arm_timer.c Peter Chubb
2011-12-05 19:53         ` andrzej zaborowski
2011-11-22  3:25       ` [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer Peter Chubb
2011-11-24 17:46         ` Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.