qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer


From: Peter Maydell
Subject: [Qemu-devel] [PATCH 1/8] Fix sp804 dual-timer
Date: Mon, 12 Dec 2011 10:47:42 +0000

From: Peter Chubb <address@hidden>

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 <address@hidden>
Signed-off-by: David Mirabito <address@hidden>
Signed-off-by: Peter Chubb <address@hidden>
Signed-off-by: Peter Maydell <address@hidden>
---
 hw/arm_timer.c |   41 +++++++++++++++++++++++++++++++++++------
 1 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 518bad2..0a5b9d2 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -170,9 +170,9 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
 }
 
 /* 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;
@@ -182,6 +182,13 @@ typedef struct {
     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)
 {
@@ -196,12 +203,27 @@ 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);
     }
+
+    /* 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,
@@ -211,9 +233,16 @@ static void sp804_write(void *opaque, target_phys_addr_t 
offset,
 
     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 = {
-- 
1.7.1




reply via email to

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