diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-10-28 09:42:06 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-10-28 09:42:06 -0400 |
commit | be6786ac738801d39cfd264ec88c352efd029578 (patch) | |
tree | 3652ce6cfbfdb1dbb8cf5a664e5e84c6d3abd260 /arch/arm | |
parent | f9cef506815386df4bd7e463b59e0a0984ce0355 (diff) | |
parent | ae6948048c417d429b8a0f85fad13e483f7cc1a3 (diff) |
Merge branch 'l2x0-pull-rmk' of git://dev.omapzoom.org/pub/scm/santosh/kernel-omap4-base into devel-stable
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/hardware/cache-l2x0.h | 9 | ||||
-rw-r--r-- | arch/arm/include/asm/outercache.h | 24 | ||||
-rw-r--r-- | arch/arm/kernel/machine_kexec.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap4-common.c | 13 | ||||
-rw-r--r-- | arch/arm/mach-ux500/cpu.c | 45 | ||||
-rw-r--r-- | arch/arm/mm/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 78 |
7 files changed, 171 insertions, 9 deletions
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index 351ca8d02aa7..cc42d5fdee17 100644 --- a/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/arch/arm/include/asm/hardware/cache-l2x0.h | |||
@@ -21,9 +21,6 @@ | |||
21 | #define __ASM_ARM_HARDWARE_L2X0_H | 21 | #define __ASM_ARM_HARDWARE_L2X0_H |
22 | 22 | ||
23 | #define L2X0_CACHE_ID 0x000 | 23 | #define L2X0_CACHE_ID 0x000 |
24 | #define L2X0_CACHE_ID_PART_MASK (0xf << 6) | ||
25 | #define L2X0_CACHE_ID_PART_L210 (1 << 6) | ||
26 | #define L2X0_CACHE_ID_PART_L310 (3 << 6) | ||
27 | #define L2X0_CACHE_TYPE 0x004 | 24 | #define L2X0_CACHE_TYPE 0x004 |
28 | #define L2X0_CTRL 0x100 | 25 | #define L2X0_CTRL 0x100 |
29 | #define L2X0_AUX_CTRL 0x104 | 26 | #define L2X0_AUX_CTRL 0x104 |
@@ -58,6 +55,12 @@ | |||
58 | #define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) | 55 | #define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) |
59 | #define L2X0_STNDBY_MODE_EN (1 << 0) | 56 | #define L2X0_STNDBY_MODE_EN (1 << 0) |
60 | 57 | ||
58 | /* Registers shifts and masks */ | ||
59 | #define L2X0_CACHE_ID_PART_MASK (0xf << 6) | ||
60 | #define L2X0_CACHE_ID_PART_L210 (1 << 6) | ||
61 | #define L2X0_CACHE_ID_PART_L310 (3 << 6) | ||
62 | #define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17) | ||
63 | |||
61 | #ifndef __ASSEMBLY__ | 64 | #ifndef __ASSEMBLY__ |
62 | extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); | 65 | extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); |
63 | #endif | 66 | #endif |
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 25f76bae57ab..fc1900925275 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h | |||
@@ -25,6 +25,9 @@ struct outer_cache_fns { | |||
25 | void (*inv_range)(unsigned long, unsigned long); | 25 | void (*inv_range)(unsigned long, unsigned long); |
26 | void (*clean_range)(unsigned long, unsigned long); | 26 | void (*clean_range)(unsigned long, unsigned long); |
27 | void (*flush_range)(unsigned long, unsigned long); | 27 | void (*flush_range)(unsigned long, unsigned long); |
28 | void (*flush_all)(void); | ||
29 | void (*inv_all)(void); | ||
30 | void (*disable)(void); | ||
28 | #ifdef CONFIG_OUTER_CACHE_SYNC | 31 | #ifdef CONFIG_OUTER_CACHE_SYNC |
29 | void (*sync)(void); | 32 | void (*sync)(void); |
30 | #endif | 33 | #endif |
@@ -50,6 +53,24 @@ static inline void outer_flush_range(unsigned long start, unsigned long end) | |||
50 | outer_cache.flush_range(start, end); | 53 | outer_cache.flush_range(start, end); |
51 | } | 54 | } |
52 | 55 | ||
56 | static inline void outer_flush_all(void) | ||
57 | { | ||
58 | if (outer_cache.flush_all) | ||
59 | outer_cache.flush_all(); | ||
60 | } | ||
61 | |||
62 | static inline void outer_inv_all(void) | ||
63 | { | ||
64 | if (outer_cache.inv_all) | ||
65 | outer_cache.inv_all(); | ||
66 | } | ||
67 | |||
68 | static inline void outer_disable(void) | ||
69 | { | ||
70 | if (outer_cache.disable) | ||
71 | outer_cache.disable(); | ||
72 | } | ||
73 | |||
53 | #else | 74 | #else |
54 | 75 | ||
55 | static inline void outer_inv_range(unsigned long start, unsigned long end) | 76 | static inline void outer_inv_range(unsigned long start, unsigned long end) |
@@ -58,6 +79,9 @@ static inline void outer_clean_range(unsigned long start, unsigned long end) | |||
58 | { } | 79 | { } |
59 | static inline void outer_flush_range(unsigned long start, unsigned long end) | 80 | static inline void outer_flush_range(unsigned long start, unsigned long end) |
60 | { } | 81 | { } |
82 | static inline void outer_flush_all(void) { } | ||
83 | static inline void outer_inv_all(void) { } | ||
84 | static inline void outer_disable(void) { } | ||
61 | 85 | ||
62 | #endif | 86 | #endif |
63 | 87 | ||
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 1fc74cbd1a19..3a8fd5140d7a 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
@@ -78,7 +78,10 @@ void machine_kexec(struct kimage *image) | |||
78 | local_fiq_disable(); | 78 | local_fiq_disable(); |
79 | setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ | 79 | setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ |
80 | flush_cache_all(); | 80 | flush_cache_all(); |
81 | outer_flush_all(); | ||
82 | outer_disable(); | ||
81 | cpu_proc_fin(); | 83 | cpu_proc_fin(); |
84 | outer_inv_all(); | ||
82 | flush_cache_all(); | 85 | flush_cache_all(); |
83 | cpu_reset(reboot_code_buffer_phys); | 86 | cpu_reset(reboot_code_buffer_phys); |
84 | } | 87 | } |
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 923f9f5f91ce..2f895553e6a8 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c | |||
@@ -44,6 +44,13 @@ void __init gic_init_irq(void) | |||
44 | } | 44 | } |
45 | 45 | ||
46 | #ifdef CONFIG_CACHE_L2X0 | 46 | #ifdef CONFIG_CACHE_L2X0 |
47 | |||
48 | static void omap4_l2x0_disable(void) | ||
49 | { | ||
50 | /* Disable PL310 L2 Cache controller */ | ||
51 | omap_smc1(0x102, 0x0); | ||
52 | } | ||
53 | |||
47 | static int __init omap_l2_cache_init(void) | 54 | static int __init omap_l2_cache_init(void) |
48 | { | 55 | { |
49 | /* | 56 | /* |
@@ -70,6 +77,12 @@ static int __init omap_l2_cache_init(void) | |||
70 | else | 77 | else |
71 | l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff); | 78 | l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff); |
72 | 79 | ||
80 | /* | ||
81 | * Override default outer_cache.disable with a OMAP4 | ||
82 | * specific one | ||
83 | */ | ||
84 | outer_cache.disable = omap4_l2x0_disable; | ||
85 | |||
73 | return 0; | 86 | return 0; |
74 | } | 87 | } |
75 | early_initcall(omap_l2_cache_init); | 88 | early_initcall(omap_l2_cache_init); |
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index e0fd747e447a..73fb1a551ec6 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/io.h> | 10 | #include <linux/io.h> |
11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
12 | 12 | ||
13 | #include <asm/cacheflush.h> | ||
13 | #include <asm/hardware/cache-l2x0.h> | 14 | #include <asm/hardware/cache-l2x0.h> |
14 | #include <asm/hardware/gic.h> | 15 | #include <asm/hardware/gic.h> |
15 | #include <asm/mach/map.h> | 16 | #include <asm/mach/map.h> |
@@ -71,6 +72,46 @@ void __init ux500_init_irq(void) | |||
71 | } | 72 | } |
72 | 73 | ||
73 | #ifdef CONFIG_CACHE_L2X0 | 74 | #ifdef CONFIG_CACHE_L2X0 |
75 | static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) | ||
76 | { | ||
77 | /* wait for the operation to complete */ | ||
78 | while (readl(reg) & mask) | ||
79 | ; | ||
80 | } | ||
81 | |||
82 | static inline void ux500_cache_sync(void) | ||
83 | { | ||
84 | void __iomem *base = __io_address(UX500_L2CC_BASE); | ||
85 | writel(0, base + L2X0_CACHE_SYNC); | ||
86 | ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * The L2 cache cannot be turned off in the non-secure world. | ||
91 | * Dummy until a secure service is in place. | ||
92 | */ | ||
93 | static void ux500_l2x0_disable(void) | ||
94 | { | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * This is only called when doing a kexec, just after turning off the L2 | ||
99 | * and L1 cache, and it is surrounded by a spinlock in the generic version. | ||
100 | * However, we're not really turning off the L2 cache right now and the | ||
101 | * PL310 does not support exclusive accesses (used to implement the spinlock). | ||
102 | * So, the invalidation needs to be done without the spinlock. | ||
103 | */ | ||
104 | static void ux500_l2x0_inv_all(void) | ||
105 | { | ||
106 | void __iomem *l2x0_base = __io_address(UX500_L2CC_BASE); | ||
107 | uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ | ||
108 | |||
109 | /* invalidate all ways */ | ||
110 | writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); | ||
111 | ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); | ||
112 | ux500_cache_sync(); | ||
113 | } | ||
114 | |||
74 | static int ux500_l2x0_init(void) | 115 | static int ux500_l2x0_init(void) |
75 | { | 116 | { |
76 | void __iomem *l2x0_base; | 117 | void __iomem *l2x0_base; |
@@ -80,6 +121,10 @@ static int ux500_l2x0_init(void) | |||
80 | /* 64KB way size, 8 way associativity, force WA */ | 121 | /* 64KB way size, 8 way associativity, force WA */ |
81 | l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); | 122 | l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); |
82 | 123 | ||
124 | /* Override invalidate function */ | ||
125 | outer_cache.disable = ux500_l2x0_disable; | ||
126 | outer_cache.inv_all = ux500_l2x0_inv_all; | ||
127 | |||
83 | return 0; | 128 | return 0; |
84 | } | 129 | } |
85 | early_initcall(ux500_l2x0_init); | 130 | early_initcall(ux500_l2x0_init); |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index a0a2928ae4dd..4414a01e1e8a 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -779,6 +779,14 @@ config CACHE_L2X0 | |||
779 | help | 779 | help |
780 | This option enables the L2x0 PrimeCell. | 780 | This option enables the L2x0 PrimeCell. |
781 | 781 | ||
782 | config CACHE_PL310 | ||
783 | bool | ||
784 | depends on CACHE_L2X0 | ||
785 | default y if CPU_V7 && !CPU_V6 | ||
786 | help | ||
787 | This option enables optimisations for the PL310 cache | ||
788 | controller. | ||
789 | |||
782 | config CACHE_TAUROS2 | 790 | config CACHE_TAUROS2 |
783 | bool "Enable the Tauros2 L2 cache controller" | 791 | bool "Enable the Tauros2 L2 cache controller" |
784 | depends on (ARCH_DOVE || ARCH_MMP) | 792 | depends on (ARCH_DOVE || ARCH_MMP) |
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 9982eb385c0f..170c9bb95866 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -28,14 +28,24 @@ | |||
28 | static void __iomem *l2x0_base; | 28 | static void __iomem *l2x0_base; |
29 | static DEFINE_SPINLOCK(l2x0_lock); | 29 | static DEFINE_SPINLOCK(l2x0_lock); |
30 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ | 30 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ |
31 | static uint32_t l2x0_size; | ||
31 | 32 | ||
32 | static inline void cache_wait(void __iomem *reg, unsigned long mask) | 33 | static inline void cache_wait_way(void __iomem *reg, unsigned long mask) |
33 | { | 34 | { |
34 | /* wait for the operation to complete */ | 35 | /* wait for cache operation by line or way to complete */ |
35 | while (readl_relaxed(reg) & mask) | 36 | while (readl_relaxed(reg) & mask) |
36 | ; | 37 | ; |
37 | } | 38 | } |
38 | 39 | ||
40 | #ifdef CONFIG_CACHE_PL310 | ||
41 | static inline void cache_wait(void __iomem *reg, unsigned long mask) | ||
42 | { | ||
43 | /* cache operations by line are atomic on PL310 */ | ||
44 | } | ||
45 | #else | ||
46 | #define cache_wait cache_wait_way | ||
47 | #endif | ||
48 | |||
39 | static inline void cache_sync(void) | 49 | static inline void cache_sync(void) |
40 | { | 50 | { |
41 | void __iomem *base = l2x0_base; | 51 | void __iomem *base = l2x0_base; |
@@ -103,14 +113,40 @@ static void l2x0_cache_sync(void) | |||
103 | spin_unlock_irqrestore(&l2x0_lock, flags); | 113 | spin_unlock_irqrestore(&l2x0_lock, flags); |
104 | } | 114 | } |
105 | 115 | ||
106 | static inline void l2x0_inv_all(void) | 116 | static void l2x0_flush_all(void) |
117 | { | ||
118 | unsigned long flags; | ||
119 | |||
120 | /* clean all ways */ | ||
121 | spin_lock_irqsave(&l2x0_lock, flags); | ||
122 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); | ||
123 | cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); | ||
124 | cache_sync(); | ||
125 | spin_unlock_irqrestore(&l2x0_lock, flags); | ||
126 | } | ||
127 | |||
128 | static void l2x0_clean_all(void) | ||
129 | { | ||
130 | unsigned long flags; | ||
131 | |||
132 | /* clean all ways */ | ||
133 | spin_lock_irqsave(&l2x0_lock, flags); | ||
134 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); | ||
135 | cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); | ||
136 | cache_sync(); | ||
137 | spin_unlock_irqrestore(&l2x0_lock, flags); | ||
138 | } | ||
139 | |||
140 | static void l2x0_inv_all(void) | ||
107 | { | 141 | { |
108 | unsigned long flags; | 142 | unsigned long flags; |
109 | 143 | ||
110 | /* invalidate all ways */ | 144 | /* invalidate all ways */ |
111 | spin_lock_irqsave(&l2x0_lock, flags); | 145 | spin_lock_irqsave(&l2x0_lock, flags); |
146 | /* Invalidating when L2 is enabled is a nono */ | ||
147 | BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1); | ||
112 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); | 148 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); |
113 | cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); | 149 | cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); |
114 | cache_sync(); | 150 | cache_sync(); |
115 | spin_unlock_irqrestore(&l2x0_lock, flags); | 151 | spin_unlock_irqrestore(&l2x0_lock, flags); |
116 | } | 152 | } |
@@ -159,6 +195,11 @@ static void l2x0_clean_range(unsigned long start, unsigned long end) | |||
159 | void __iomem *base = l2x0_base; | 195 | void __iomem *base = l2x0_base; |
160 | unsigned long flags; | 196 | unsigned long flags; |
161 | 197 | ||
198 | if ((end - start) >= l2x0_size) { | ||
199 | l2x0_clean_all(); | ||
200 | return; | ||
201 | } | ||
202 | |||
162 | spin_lock_irqsave(&l2x0_lock, flags); | 203 | spin_lock_irqsave(&l2x0_lock, flags); |
163 | start &= ~(CACHE_LINE_SIZE - 1); | 204 | start &= ~(CACHE_LINE_SIZE - 1); |
164 | while (start < end) { | 205 | while (start < end) { |
@@ -184,6 +225,11 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
184 | void __iomem *base = l2x0_base; | 225 | void __iomem *base = l2x0_base; |
185 | unsigned long flags; | 226 | unsigned long flags; |
186 | 227 | ||
228 | if ((end - start) >= l2x0_size) { | ||
229 | l2x0_flush_all(); | ||
230 | return; | ||
231 | } | ||
232 | |||
187 | spin_lock_irqsave(&l2x0_lock, flags); | 233 | spin_lock_irqsave(&l2x0_lock, flags); |
188 | start &= ~(CACHE_LINE_SIZE - 1); | 234 | start &= ~(CACHE_LINE_SIZE - 1); |
189 | while (start < end) { | 235 | while (start < end) { |
@@ -206,10 +252,20 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
206 | spin_unlock_irqrestore(&l2x0_lock, flags); | 252 | spin_unlock_irqrestore(&l2x0_lock, flags); |
207 | } | 253 | } |
208 | 254 | ||
255 | static void l2x0_disable(void) | ||
256 | { | ||
257 | unsigned long flags; | ||
258 | |||
259 | spin_lock_irqsave(&l2x0_lock, flags); | ||
260 | writel(0, l2x0_base + L2X0_CTRL); | ||
261 | spin_unlock_irqrestore(&l2x0_lock, flags); | ||
262 | } | ||
263 | |||
209 | void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | 264 | void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) |
210 | { | 265 | { |
211 | __u32 aux; | 266 | __u32 aux; |
212 | __u32 cache_id; | 267 | __u32 cache_id; |
268 | __u32 way_size = 0; | ||
213 | int ways; | 269 | int ways; |
214 | const char *type; | 270 | const char *type; |
215 | 271 | ||
@@ -244,6 +300,13 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
244 | l2x0_way_mask = (1 << ways) - 1; | 300 | l2x0_way_mask = (1 << ways) - 1; |
245 | 301 | ||
246 | /* | 302 | /* |
303 | * L2 cache Size = Way size * Number of ways | ||
304 | */ | ||
305 | way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17; | ||
306 | way_size = 1 << (way_size + 3); | ||
307 | l2x0_size = ways * way_size * SZ_1K; | ||
308 | |||
309 | /* | ||
247 | * Check if l2x0 controller is already enabled. | 310 | * Check if l2x0 controller is already enabled. |
248 | * If you are booting from non-secure mode | 311 | * If you are booting from non-secure mode |
249 | * accessing the below registers will fault. | 312 | * accessing the below registers will fault. |
@@ -263,8 +326,11 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
263 | outer_cache.clean_range = l2x0_clean_range; | 326 | outer_cache.clean_range = l2x0_clean_range; |
264 | outer_cache.flush_range = l2x0_flush_range; | 327 | outer_cache.flush_range = l2x0_flush_range; |
265 | outer_cache.sync = l2x0_cache_sync; | 328 | outer_cache.sync = l2x0_cache_sync; |
329 | outer_cache.flush_all = l2x0_flush_all; | ||
330 | outer_cache.inv_all = l2x0_inv_all; | ||
331 | outer_cache.disable = l2x0_disable; | ||
266 | 332 | ||
267 | printk(KERN_INFO "%s cache controller enabled\n", type); | 333 | printk(KERN_INFO "%s cache controller enabled\n", type); |
268 | printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", | 334 | printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", |
269 | ways, cache_id, aux); | 335 | ways, cache_id, aux, l2x0_size); |
270 | } | 336 | } |