1/* 2 * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support 3 * 4 * Copyright (C) 2007 ARM Limited 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19#include <linux/init.h> 20 21#include <asm/cacheflush.h> 22#include <asm/io.h> 23#include <asm/hardware/cache-l2x0.h> 24 25#define CACHE_LINE_SIZE 32 26 27static void __iomem *l2x0_base; 28 29static inline void sync_writel(unsigned long val, unsigned long reg, 30 unsigned long complete_mask) 31{ 32 writel(val, l2x0_base + reg); 33 /* wait for the operation to complete */ 34 while (readl(l2x0_base + reg) & complete_mask) 35 ; 36} 37 38static inline void cache_sync(void) 39{ 40 sync_writel(0, L2X0_CACHE_SYNC, 1); 41} 42 43static inline void l2x0_inv_all(void) 44{ 45 /* invalidate all ways */ 46 sync_writel(0xff, L2X0_INV_WAY, 0xff); 47 cache_sync(); 48} 49 50static void l2x0_inv_range(unsigned long start, unsigned long end) 51{ 52 unsigned long addr; 53 54 start &= ~(CACHE_LINE_SIZE - 1); 55 for (addr = start; addr < end; addr += CACHE_LINE_SIZE) 56 sync_writel(addr, L2X0_INV_LINE_PA, 1); 57 cache_sync(); 58} 59 60static void l2x0_clean_range(unsigned long start, unsigned long end) 61{ 62 unsigned long addr; 63 64 start &= ~(CACHE_LINE_SIZE - 1); 65 for (addr = start; addr < end; addr += CACHE_LINE_SIZE) 66 sync_writel(addr, L2X0_CLEAN_LINE_PA, 1); 67 cache_sync(); 68} 69 70static void l2x0_flush_range(unsigned long start, unsigned long end) 71{ 72 unsigned long addr; 73 74 start &= ~(CACHE_LINE_SIZE - 1); 75 for (addr = start; addr < end; addr += CACHE_LINE_SIZE) 76 sync_writel(addr, L2X0_CLEAN_INV_LINE_PA, 1); 77 cache_sync(); 78} 79 80void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) 81{ 82 __u32 aux; 83 84 l2x0_base = base; 85 86 /* disable L2X0 */ 87 writel(0, l2x0_base + L2X0_CTRL); 88 89 aux = readl(l2x0_base + L2X0_AUX_CTRL); 90 aux &= aux_mask; 91 aux |= aux_val; 92 writel(aux, l2x0_base + L2X0_AUX_CTRL); 93 94 l2x0_inv_all(); 95 96 /* enable L2X0 */ 97 writel(1, l2x0_base + L2X0_CTRL); 98 99 outer_cache.inv_range = l2x0_inv_range; 100 outer_cache.clean_range = l2x0_clean_range; 101 outer_cache.flush_range = l2x0_flush_range; 102 103 printk(KERN_INFO "L2X0 cache controller enabled\n"); 104} 105