diff mbox

Implement RCC2 in Stellaris v2

Message ID 4A86571F.7030809@bravegnu.org
State Superseded
Headers show

Commit Message

Vijay Kumar Aug. 15, 2009, 6:35 a.m. UTC
Code from Stellarisware fails to execute in qemu, since it tries to
read/write to RCC2, that is not available in the Sandstorm register
interface. But the Stellarisware code assumes that the processor
ignores writes to RCC2 and reads return 0. This patch implements the
RCC2 register, which provides the required behaviour in the Fury and
Sandstorm interface.

Changes in v2:

  * Added load support from both version 1 and version 2 saves.

Initial Version:

  * Added RCC2 register in the SYSCTL block.
  * Moved Sandstorm and Fury identification helper functions.
  * Save and restore RCC2.

Signed-off-by: Vijay Kumar B. <vijaykumar@bravegnu.org>
diff mbox

Patch

Index: qemu/hw/stellaris.c
===================================================================
--- qemu.orig/hw/stellaris.c	2009-08-15 10:12:30.000000000 +0530
+++ qemu/hw/stellaris.c	2009-08-15 11:47:42.000000000 +0530
@@ -7,6 +7,8 @@ 
  * This code is licenced under the GPL.
  */
 
+#include <stdbool.h>
+
 #include "sysbus.h"
 #include "ssi.h"
 #include "arm-misc.h"
@@ -367,6 +369,7 @@ 
     uint32_t int_mask;
     uint32_t resc;
     uint32_t rcc;
+    uint32_t rcc2;
     uint32_t rcgc[3];
     uint32_t scgc[3];
     uint32_t dcgc[3];
@@ -421,6 +424,36 @@ 
     0xb11c /* 8.192 Mhz */
 };
 
+#define DID0_VER_MASK        0x70000000
+#define DID0_VER_0           0x00000000
+#define DID0_VER_1           0x10000000
+
+#define DID0_CLASS_MASK      0x00FF0000
+#define DID0_CLASS_SANDSTORM 0x00000000
+#define DID0_CLASS_FURY      0x00010000
+
+static bool ssys_is_sandstorm(ssys_state *s)
+{
+    uint32_t did0 = s->board->did0;
+
+    switch (did0 & DID0_VER_MASK) {
+    case DID0_VER_0:
+	return 1;
+    case DID0_VER_1:
+	return ((did0 & DID0_CLASS_MASK) == DID0_CLASS_SANDSTORM);
+    default:
+	return 0;
+    }
+}
+
+static bool ssys_is_fury(ssys_state *s)
+{
+    uint32_t did0 = s->board->did0;
+
+    return (((did0 & DID0_VER_MASK) == DID0_VER_1)
+	    && ((did0 & DID0_CLASS_MASK) == DID0_CLASS_FURY));
+}
+
 static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
 {
     ssys_state *s = (ssys_state *)opaque;
@@ -464,12 +497,14 @@ 
         {
             int xtal;
             xtal = (s->rcc >> 6) & 0xf;
-            if (s->board->did0 & (1 << 16)) {
+            if (ssys_is_fury(s)) {
                 return pllcfg_fury[xtal];
             } else {
                 return pllcfg_sandstorm[xtal];
             }
         }
+    case 0x070: /* RCC2 */
+        return s->rcc2;
     case 0x100: /* RCGC0 */
         return s->rcgc[0];
     case 0x104: /* RCGC1 */
@@ -502,9 +537,21 @@ 
     }
 }
 
+static bool ssys_use_rcc2(ssys_state *s)
+{
+    return (s->rcc2 >> 31) & 0x1;
+}
+
+/*
+ * Caculate the sys. clock period in ms.
+ */
 static void ssys_calculate_system_clock(ssys_state *s)
 {
-    system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+    if (ssys_use_rcc2(s)) {
+	system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
+    } else {
+	system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+    }
 }
 
 static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
@@ -540,6 +587,17 @@ 
         s->rcc = value;
         ssys_calculate_system_clock(s);
         break;
+    case 0x070: /* RCC2 */
+        if (ssys_is_sandstorm(s))
+	    break;
+
+        if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
+            /* PLL enable.  */
+            s->int_status |= (1 << 6);
+        }
+	s->rcc2 = value;
+	ssys_calculate_system_clock(s);
+	break;
     case 0x100: /* RCGC0 */
         s->rcgc[0] = value;
         break;
@@ -597,6 +655,12 @@ 
 
     s->pborctl = 0x7ffd;
     s->rcc = 0x078e3ac0;
+
+    if (ssys_is_sandstorm(s))
+	s->rcc2 = 0;
+    else
+	s->rcc2 = 0x07802810;
+
     s->rcgc[0] = 1;
     s->scgc[0] = 1;
     s->dcgc[0] = 1;
@@ -612,6 +676,7 @@ 
     qemu_put_be32(f, s->int_status);
     qemu_put_be32(f, s->resc);
     qemu_put_be32(f, s->rcc);
+    qemu_put_be32(f, s->rcc2);
     qemu_put_be32(f, s->rcgc[0]);
     qemu_put_be32(f, s->rcgc[1]);
     qemu_put_be32(f, s->rcgc[2]);
@@ -629,7 +694,7 @@ 
 {
     ssys_state *s = (ssys_state *)opaque;
 
-    if (version_id != 1)
+    if (version_id != 1 && version_id != 2)
         return -EINVAL;
 
     s->pborctl = qemu_get_be32(f);
@@ -638,6 +703,12 @@ 
     s->int_status = qemu_get_be32(f);
     s->resc = qemu_get_be32(f);
     s->rcc = qemu_get_be32(f);
+
+    if (version_id == 2)
+        s->rcc2 = qemu_get_be32(f);
+    else
+        s->rcc2 = 0;
+
     s->rcgc[0] = qemu_get_be32(f);
     s->rcgc[1] = qemu_get_be32(f);
     s->rcgc[2] = qemu_get_be32(f);
@@ -672,7 +743,7 @@ 
                                        ssys_writefn, s);
     cpu_register_physical_memory(base, 0x00001000, iomemtype);
     ssys_reset(s);
-    register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s);
+    register_savevm("stellaris_sys", -1, 2, ssys_save, ssys_load, s);
 }