[ARM] cache_l2x0: add shutdown and restart functions
authorGary King <gking@nvidia.com>
Mon, 28 Jun 2010 23:23:01 +0000 (16:23 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:26:15 +0000 (16:26 -0700)
Add shutdown and restart functions to the L2X0 outer cache controller,
so that machines which need to flush and disable the outer cache
controller prior to executing the architecture reset or platform
suspend code can do so.

Change-Id: I042aae121e7ba75223ed502afb4d118b0441597e
Signed-off-by: Gary King <gking@nvidia.com>
Signed-off-by: Colin Cross <ccross@android.com>
arch/arm/include/asm/hardware/cache-l2x0.h
arch/arm/mm/cache-l2x0.c

index 3161a79d136e462399131465123153250b70175a..89e2ff8a3585c5c999737acb5112d15bb555083d 100644 (file)
@@ -57,6 +57,8 @@
 
 #ifndef __ASSEMBLY__
 extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
+extern void l2x0_shutdown(void);
+extern void l2x0_restart(void);
 #endif
 
 #endif
index e3afae0e07898bf7a6f55da00f877414b3e55d02..9eb79d84b4602983371d7c7f06a551a16fb10a84 100644 (file)
@@ -142,6 +142,18 @@ static inline void l2x0_inv_all(void)
        _l2x0_unlock(&l2x0_lock, flags);
 }
 
+static inline void l2x0_flush_all(void)
+{
+       unsigned long flags;
+
+       /* flush all ways */
+       _l2x0_lock(&l2x0_lock, flags);
+       writel(0xff, l2x0_base + L2X0_CLEAN_INV_WAY);
+       cache_wait_always(l2x0_base + L2X0_CLEAN_INV_WAY, 0xff);
+       cache_sync();
+       _l2x0_unlock(&l2x0_lock, flags);
+}
+
 static void l2x0_inv_range(unsigned long start, unsigned long end)
 {
        void __iomem *base = l2x0_base;
@@ -233,15 +245,43 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
        _l2x0_unlock(&l2x0_lock, flags);
 }
 
-void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+void l2x0_shutdown(void)
+{
+       unsigned long flags;
+
+       BUG_ON(num_online_cpus() > 1);
+
+       local_irq_save(flags);
+
+       if (readl(l2x0_base + L2X0_CTRL) & 1) {
+               int m;
+               /* lockdown all ways, all masters to prevent new line
+                * allocation during maintenance */
+               for (m=0; m<8; m++) {
+                       writel(l2x0_way_mask,
+                              l2x0_base + L2X0_LOCKDOWN_WAY_D + (m*8));
+                       writel(l2x0_way_mask,
+                              l2x0_base + L2X0_LOCKDOWN_WAY_I + (m*8));
+               }
+               l2x0_flush_all();
+               writel(0, l2x0_base + L2X0_CTRL);
+               /* unlock cache ways */
+               for (m=0; m<8; m++) {
+                       writel(0, l2x0_base + L2X0_LOCKDOWN_WAY_D + (m*8));
+                       writel(0, l2x0_base + L2X0_LOCKDOWN_WAY_I + (m*8));
+               }
+       }
+
+       local_irq_restore(flags);
+}
+
+static void l2x0_enable(__u32 aux_val, __u32 aux_mask)
 {
        __u32 aux;
        __u32 cache_id;
        int ways;
        const char *type;
 
-       l2x0_base = base;
-
        cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
        aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 
@@ -286,12 +326,24 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
                writel_relaxed(1, l2x0_base + L2X0_CTRL);
        }
 
+       /*printk(KERN_INFO "%s cache controller enabled\n", type);
+       printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
+                        ways, cache_id, aux);*/
+}
+
+void l2x0_restart(void)
+{
+       l2x0_enable(0, ~0ul);
+}
+
+void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+{
+       l2x0_base = base;
+
+       l2x0_enable(aux_val, aux_mask);
+
        outer_cache.inv_range = l2x0_inv_range;
        outer_cache.clean_range = l2x0_clean_range;
        outer_cache.flush_range = l2x0_flush_range;
        outer_cache.sync = l2x0_cache_sync;
-
-       printk(KERN_INFO "%s cache controller enabled\n", type);
-       printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
-                        ways, cache_id, aux);
 }