#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;
{
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)
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)
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);
}
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);
}
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)
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);
}
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)
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) {
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);
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);