diff options
Diffstat (limited to 'arch/arm/mm/cache-l2x0.c')
| -rw-r--r-- | arch/arm/mm/cache-l2x0.c | 72 | 
1 files changed, 62 insertions, 10 deletions
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index cb8fc6573b1..07334632d3e 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -42,6 +42,57 @@ static inline void cache_sync(void)  	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(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(addr, base + L2X0_INV_LINE_PA); +} + +#ifdef CONFIG_PL310_ERRATA_588369 +static void debug_writel(unsigned long val) +{ +	extern void omap_smc1(u32 fn, u32 arg); + +	/* +	 * Texas Instrument secure monitor api to modify the +	 * PL310 Debug Control Register. +	 */ +	omap_smc1(0x100, val); +} + +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(addr, base + L2X0_CLEAN_LINE_PA); +	cache_wait(base + L2X0_INV_LINE_PA, 1); +	writel(addr, base + L2X0_INV_LINE_PA); +} +#else + +/* Optimised out for non-errata case */ +static inline void debug_writel(unsigned long val) +{ +} + +static inline void l2x0_flush_line(unsigned long addr) +{ +	void __iomem *base = l2x0_base; +	cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); +	writel(addr, base + L2X0_CLEAN_INV_LINE_PA); +} +#endif +  static inline void l2x0_inv_all(void)  {  	unsigned long flags; @@ -62,23 +113,24 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)  	spin_lock_irqsave(&l2x0_lock, flags);  	if (start & (CACHE_LINE_SIZE - 1)) {  		start &= ~(CACHE_LINE_SIZE - 1); -		cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); -		writel(start, base + L2X0_CLEAN_INV_LINE_PA); +		debug_writel(0x03); +		l2x0_flush_line(start); +		debug_writel(0x00);  		start += CACHE_LINE_SIZE;  	}  	if (end & (CACHE_LINE_SIZE - 1)) {  		end &= ~(CACHE_LINE_SIZE - 1); -		cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); -		writel(end, base + L2X0_CLEAN_INV_LINE_PA); +		debug_writel(0x03); +		l2x0_flush_line(end); +		debug_writel(0x00);  	}  	while (start < end) {  		unsigned long blk_end = start + min(end - start, 4096UL);  		while (start < blk_end) { -			cache_wait(base + L2X0_INV_LINE_PA, 1); -			writel(start, base + L2X0_INV_LINE_PA); +			l2x0_inv_line(start);  			start += CACHE_LINE_SIZE;  		} @@ -103,8 +155,7 @@ static void l2x0_clean_range(unsigned long start, unsigned long end)  		unsigned long blk_end = start + min(end - start, 4096UL);  		while (start < blk_end) { -			cache_wait(base + L2X0_CLEAN_LINE_PA, 1); -			writel(start, base + L2X0_CLEAN_LINE_PA); +			l2x0_clean_line(start);  			start += CACHE_LINE_SIZE;  		} @@ -128,11 +179,12 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)  	while (start < end) {  		unsigned long blk_end = start + min(end - start, 4096UL); +		debug_writel(0x03);  		while (start < blk_end) { -			cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); -			writel(start, base + L2X0_CLEAN_INV_LINE_PA); +			l2x0_flush_line(start);  			start += CACHE_LINE_SIZE;  		} +		debug_writel(0x00);  		if (blk_end < end) {  			spin_unlock_irqrestore(&l2x0_lock, flags);  |