| 
					
				 | 
			
			
				@@ -0,0 +1,149 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright (C) 2007 ARM Limited 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * This program is free software; you can redistribute it and/or modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * it under the terms of the GNU General Public License version 2 as 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * published by the Free Software Foundation. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * This program is distributed in the hope that it will be useful, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * GNU General Public License for more details. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * You should have received a copy of the GNU General Public License 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * along with this program; if not, write to the Free Software 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/err.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/init.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/spinlock.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/io.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/of.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <linux/of_address.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <asm/cacheflush.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <asm/hardware/cache-l2x0.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "cache-aurora-l2.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define CACHE_LINE_SIZE		32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void __iomem *l2x0_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static DEFINE_RAW_SPINLOCK(l2x0_lock); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 l2x0_way_mask;	/* Bitmask of active ways */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32 l2x0_size; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static unsigned long sync_reg_offset = L2X0_CACHE_SYNC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Aurora don't have the cache ID register available, so we have to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * pass it though the device tree */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static u32  cache_id_part_number_from_dt; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct l2x0_regs l2x0_saved_regs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct l2x0_of_data { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (*setup)(const struct device_node *, u32 *, u32 *); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void (*save)(void); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	struct outer_cache_fns outer_cache; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static bool of_init = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void cache_wait_way(void __iomem *reg, unsigned long mask) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* wait for cache operation by line or way to complete */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	while (readl_relaxed(reg) & mask) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		cpu_relax(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef CONFIG_CACHE_PL310 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void cache_wait(void __iomem *reg, unsigned long mask) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* cache operations by line are atomic on PL310 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define cache_wait	cache_wait_way 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void cache_sync(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void __iomem *base = l2x0_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(0, base + sync_reg_offset); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait(base + L2X0_CACHE_SYNC, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void l2x0_clean_line(unsigned long addr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void __iomem *base = l2x0_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait(base + L2X0_CLEAN_LINE_PA, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void l2x0_inv_line(unsigned long addr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void __iomem *base = l2x0_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait(base + L2X0_INV_LINE_PA, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(addr, base + L2X0_INV_LINE_PA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void debug_writel(unsigned long val) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (outer_cache.set_debug) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		outer_cache.set_debug(val); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void pl310_set_debug(unsigned long val) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Optimised out for non-errata case */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void debug_writel(unsigned long val) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define pl310_set_debug	NULL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifdef CONFIG_PL310_ERRATA_588369 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void l2x0_flush_line(unsigned long addr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void __iomem *base = l2x0_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* Clean by PA followed by Invalidate by PA */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait(base + L2X0_CLEAN_LINE_PA, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait(base + L2X0_INV_LINE_PA, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(addr, base + L2X0_INV_LINE_PA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline void l2x0_flush_line(unsigned long addr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	void __iomem *base = l2x0_base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(addr, base + L2X0_CLEAN_INV_LINE_PA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void l2x0_cache_sync(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	raw_spin_lock_irqsave(&l2x0_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_sync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	raw_spin_unlock_irqrestore(&l2x0_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void __l2x0_flush_all(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	debug_writel(0x03); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	cache_sync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	debug_writel(0x00); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void l2x0_flush_all(void) 
			 |