Merge branch 'linux-tegra-2.6.36' into android-tegra-2.6.36
[firefly-linux-kernel-4.4.55.git] / arch / arm / mm / cache-l2x0.c
index 9982eb385c0f9844d70f53d45c7377fcf5fa2887..9abfa5d2b750654faf823ae6e74c12dec6396f45 100644 (file)
 #define CACHE_LINE_SIZE                32
 
 static void __iomem *l2x0_base;
-static DEFINE_SPINLOCK(l2x0_lock);
 static uint32_t l2x0_way_mask; /* Bitmask of active ways */
+bool l2x0_disabled;
 
-static inline void cache_wait(void __iomem *reg, unsigned long mask)
+static inline void cache_wait_always(void __iomem *reg, unsigned long mask)
 {
        /* wait for the operation to complete */
        while (readl_relaxed(reg) & mask)
                ;
 }
 
+#ifdef CONFIG_CACHE_PL310
+
+static inline void cache_wait(void __iomem *reg, unsigned long mask)
+{
+       /* cache operations are atomic */
+}
+
+#define _l2x0_lock(lock, flags)                ((void)(flags))
+#define _l2x0_unlock(lock, flags)      ((void)(flags))
+
+#define block_end(start, end)          (end)
+
+#define L2CC_TYPE                      "PL310/L2C-310"
+
+#else  /* !CONFIG_CACHE_PL310 */
+
+#define cache_wait                     cache_wait_always
+
+static DEFINE_SPINLOCK(l2x0_lock);
+#define _l2x0_lock(lock, flags)                spin_lock_irqsave(lock, flags)
+#define _l2x0_unlock(lock, flags)      spin_unlock_irqrestore(lock, flags)
+
+#define block_end(start, end)          ((start) + min((end) - (start), 4096UL))
+
+#define L2CC_TYPE                      "L2x0"
+
+#endif /* CONFIG_CACHE_PL310 */
+
 static inline void cache_sync(void)
 {
        void __iomem *base = l2x0_base;
@@ -98,9 +126,9 @@ static void l2x0_cache_sync(void)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&l2x0_lock, flags);
+       _l2x0_lock(&l2x0_lock, flags);
        cache_sync();
-       spin_unlock_irqrestore(&l2x0_lock, flags);
+       _l2x0_unlock(&l2x0_lock, flags);
 }
 
 static inline void l2x0_inv_all(void)
@@ -108,11 +136,23 @@ static inline void l2x0_inv_all(void)
        unsigned long flags;
 
        /* invalidate all ways */
-       spin_lock_irqsave(&l2x0_lock, flags);
+       _l2x0_lock(&l2x0_lock, flags);
        writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
-       cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
+       cache_wait_always(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
        cache_sync();
-       spin_unlock_irqrestore(&l2x0_lock, flags);
+       _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)
@@ -120,7 +160,7 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
        void __iomem *base = l2x0_base;
        unsigned long flags;
 
-       spin_lock_irqsave(&l2x0_lock, flags);
+       _l2x0_lock(&l2x0_lock, flags);
        if (start & (CACHE_LINE_SIZE - 1)) {
                start &= ~(CACHE_LINE_SIZE - 1);
                debug_writel(0x03);
@@ -137,7 +177,7 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
        }
 
        while (start < end) {
-               unsigned long blk_end = start + min(end - start, 4096UL);
+               unsigned long blk_end = block_end(start, end);
 
                while (start < blk_end) {
                        l2x0_inv_line(start);
@@ -145,13 +185,13 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
                }
 
                if (blk_end < end) {
-                       spin_unlock_irqrestore(&l2x0_lock, flags);
-                       spin_lock_irqsave(&l2x0_lock, flags);
+                       _l2x0_unlock(&l2x0_lock, flags);
+                       _l2x0_lock(&l2x0_lock, flags);
                }
        }
        cache_wait(base + L2X0_INV_LINE_PA, 1);
        cache_sync();
-       spin_unlock_irqrestore(&l2x0_lock, flags);
+       _l2x0_unlock(&l2x0_lock, flags);
 }
 
 static void l2x0_clean_range(unsigned long start, unsigned long end)
@@ -159,10 +199,10 @@ static void l2x0_clean_range(unsigned long start, unsigned long end)
        void __iomem *base = l2x0_base;
        unsigned long flags;
 
-       spin_lock_irqsave(&l2x0_lock, flags);
+       _l2x0_lock(&l2x0_lock, flags);
        start &= ~(CACHE_LINE_SIZE - 1);
        while (start < end) {
-               unsigned long blk_end = start + min(end - start, 4096UL);
+               unsigned long blk_end = block_end(start, end);
 
                while (start < blk_end) {
                        l2x0_clean_line(start);
@@ -170,13 +210,13 @@ static void l2x0_clean_range(unsigned long start, unsigned long end)
                }
 
                if (blk_end < end) {
-                       spin_unlock_irqrestore(&l2x0_lock, flags);
-                       spin_lock_irqsave(&l2x0_lock, flags);
+                       _l2x0_unlock(&l2x0_lock, flags);
+                       _l2x0_lock(&l2x0_lock, flags);
                }
        }
        cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
        cache_sync();
-       spin_unlock_irqrestore(&l2x0_lock, flags);
+       _l2x0_unlock(&l2x0_lock, flags);
 }
 
 static void l2x0_flush_range(unsigned long start, unsigned long end)
@@ -184,10 +224,10 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
        void __iomem *base = l2x0_base;
        unsigned long flags;
 
-       spin_lock_irqsave(&l2x0_lock, flags);
+       _l2x0_lock(&l2x0_lock, flags);
        start &= ~(CACHE_LINE_SIZE - 1);
        while (start < end) {
-               unsigned long blk_end = start + min(end - start, 4096UL);
+               unsigned long blk_end = block_end(start, end);
 
                debug_writel(0x03);
                while (start < blk_end) {
@@ -197,23 +237,57 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
                debug_writel(0x00);
 
                if (blk_end < end) {
-                       spin_unlock_irqrestore(&l2x0_lock, flags);
-                       spin_lock_irqsave(&l2x0_lock, flags);
+                       _l2x0_unlock(&l2x0_lock, flags);
+                       _l2x0_lock(&l2x0_lock, flags);
                }
        }
        cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
        cache_sync();
-       spin_unlock_irqrestore(&l2x0_lock, flags);
+       _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;
+
+       if (l2x0_disabled)
+               return;
+
+       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;
+       if (l2x0_disabled)
+               return;
 
        cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
        aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
@@ -259,12 +333,36 @@ 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)
+{
+       if (l2x0_disabled) {
+               pr_info(L2CC_TYPE " cache controller disabled\n");
+               return;
+       }
+
+       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);
+static int __init l2x0_disable(char *unused)
+{
+       l2x0_disabled = 1;
+       return 0;
 }
+early_param("nol2x0", l2x0_disable);