diff options
Diffstat (limited to 'arch/arm/mm/cache-l2x0.c')
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 262 |
1 files changed, 237 insertions, 25 deletions
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 9ecfdb511951..8ac9e9f84790 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -16,9 +16,12 @@ | |||
16 | * along with this program; if not, write to the Free Software | 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 | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | #include <linux/err.h> | ||
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
21 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_address.h> | ||
22 | 25 | ||
23 | #include <asm/cacheflush.h> | 26 | #include <asm/cacheflush.h> |
24 | #include <asm/hardware/cache-l2x0.h> | 27 | #include <asm/hardware/cache-l2x0.h> |
@@ -26,15 +29,23 @@ | |||
26 | #define CACHE_LINE_SIZE 32 | 29 | #define CACHE_LINE_SIZE 32 |
27 | 30 | ||
28 | static void __iomem *l2x0_base; | 31 | static void __iomem *l2x0_base; |
29 | static DEFINE_SPINLOCK(l2x0_lock); | 32 | static DEFINE_RAW_SPINLOCK(l2x0_lock); |
30 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ | 33 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ |
31 | static uint32_t l2x0_size; | 34 | static uint32_t l2x0_size; |
32 | 35 | ||
36 | struct l2x0_regs l2x0_saved_regs; | ||
37 | |||
38 | struct l2x0_of_data { | ||
39 | void (*setup)(const struct device_node *, __u32 *, __u32 *); | ||
40 | void (*save)(void); | ||
41 | void (*resume)(void); | ||
42 | }; | ||
43 | |||
33 | static inline void cache_wait_way(void __iomem *reg, unsigned long mask) | 44 | static inline void cache_wait_way(void __iomem *reg, unsigned long mask) |
34 | { | 45 | { |
35 | /* wait for cache operation by line or way to complete */ | 46 | /* wait for cache operation by line or way to complete */ |
36 | while (readl_relaxed(reg) & mask) | 47 | while (readl_relaxed(reg) & mask) |
37 | ; | 48 | cpu_relax(); |
38 | } | 49 | } |
39 | 50 | ||
40 | #ifdef CONFIG_CACHE_PL310 | 51 | #ifdef CONFIG_CACHE_PL310 |
@@ -115,9 +126,9 @@ static void l2x0_cache_sync(void) | |||
115 | { | 126 | { |
116 | unsigned long flags; | 127 | unsigned long flags; |
117 | 128 | ||
118 | spin_lock_irqsave(&l2x0_lock, flags); | 129 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
119 | cache_sync(); | 130 | cache_sync(); |
120 | spin_unlock_irqrestore(&l2x0_lock, flags); | 131 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
121 | } | 132 | } |
122 | 133 | ||
123 | static void __l2x0_flush_all(void) | 134 | static void __l2x0_flush_all(void) |
@@ -134,9 +145,9 @@ static void l2x0_flush_all(void) | |||
134 | unsigned long flags; | 145 | unsigned long flags; |
135 | 146 | ||
136 | /* clean all ways */ | 147 | /* clean all ways */ |
137 | spin_lock_irqsave(&l2x0_lock, flags); | 148 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
138 | __l2x0_flush_all(); | 149 | __l2x0_flush_all(); |
139 | spin_unlock_irqrestore(&l2x0_lock, flags); | 150 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
140 | } | 151 | } |
141 | 152 | ||
142 | static void l2x0_clean_all(void) | 153 | static void l2x0_clean_all(void) |
@@ -144,11 +155,11 @@ static void l2x0_clean_all(void) | |||
144 | unsigned long flags; | 155 | unsigned long flags; |
145 | 156 | ||
146 | /* clean all ways */ | 157 | /* clean all ways */ |
147 | spin_lock_irqsave(&l2x0_lock, flags); | 158 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
148 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); | 159 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); |
149 | cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); | 160 | cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); |
150 | cache_sync(); | 161 | cache_sync(); |
151 | spin_unlock_irqrestore(&l2x0_lock, flags); | 162 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
152 | } | 163 | } |
153 | 164 | ||
154 | static void l2x0_inv_all(void) | 165 | static void l2x0_inv_all(void) |
@@ -156,13 +167,13 @@ static void l2x0_inv_all(void) | |||
156 | unsigned long flags; | 167 | unsigned long flags; |
157 | 168 | ||
158 | /* invalidate all ways */ | 169 | /* invalidate all ways */ |
159 | spin_lock_irqsave(&l2x0_lock, flags); | 170 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
160 | /* Invalidating when L2 is enabled is a nono */ | 171 | /* Invalidating when L2 is enabled is a nono */ |
161 | BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1); | 172 | BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1); |
162 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); | 173 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); |
163 | cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); | 174 | cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); |
164 | cache_sync(); | 175 | cache_sync(); |
165 | spin_unlock_irqrestore(&l2x0_lock, flags); | 176 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
166 | } | 177 | } |
167 | 178 | ||
168 | static void l2x0_inv_range(unsigned long start, unsigned long end) | 179 | static void l2x0_inv_range(unsigned long start, unsigned long end) |
@@ -170,7 +181,7 @@ static void l2x0_inv_range(unsigned long start, unsigned long end) | |||
170 | void __iomem *base = l2x0_base; | 181 | void __iomem *base = l2x0_base; |
171 | unsigned long flags; | 182 | unsigned long flags; |
172 | 183 | ||
173 | spin_lock_irqsave(&l2x0_lock, flags); | 184 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
174 | if (start & (CACHE_LINE_SIZE - 1)) { | 185 | if (start & (CACHE_LINE_SIZE - 1)) { |
175 | start &= ~(CACHE_LINE_SIZE - 1); | 186 | start &= ~(CACHE_LINE_SIZE - 1); |
176 | debug_writel(0x03); | 187 | debug_writel(0x03); |
@@ -195,13 +206,13 @@ static void l2x0_inv_range(unsigned long start, unsigned long end) | |||
195 | } | 206 | } |
196 | 207 | ||
197 | if (blk_end < end) { | 208 | if (blk_end < end) { |
198 | spin_unlock_irqrestore(&l2x0_lock, flags); | 209 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
199 | spin_lock_irqsave(&l2x0_lock, flags); | 210 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
200 | } | 211 | } |
201 | } | 212 | } |
202 | cache_wait(base + L2X0_INV_LINE_PA, 1); | 213 | cache_wait(base + L2X0_INV_LINE_PA, 1); |
203 | cache_sync(); | 214 | cache_sync(); |
204 | spin_unlock_irqrestore(&l2x0_lock, flags); | 215 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
205 | } | 216 | } |
206 | 217 | ||
207 | static void l2x0_clean_range(unsigned long start, unsigned long end) | 218 | static void l2x0_clean_range(unsigned long start, unsigned long end) |
@@ -214,7 +225,7 @@ static void l2x0_clean_range(unsigned long start, unsigned long end) | |||
214 | return; | 225 | return; |
215 | } | 226 | } |
216 | 227 | ||
217 | spin_lock_irqsave(&l2x0_lock, flags); | 228 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
218 | start &= ~(CACHE_LINE_SIZE - 1); | 229 | start &= ~(CACHE_LINE_SIZE - 1); |
219 | while (start < end) { | 230 | while (start < end) { |
220 | unsigned long blk_end = start + min(end - start, 4096UL); | 231 | unsigned long blk_end = start + min(end - start, 4096UL); |
@@ -225,13 +236,13 @@ static void l2x0_clean_range(unsigned long start, unsigned long end) | |||
225 | } | 236 | } |
226 | 237 | ||
227 | if (blk_end < end) { | 238 | if (blk_end < end) { |
228 | spin_unlock_irqrestore(&l2x0_lock, flags); | 239 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
229 | spin_lock_irqsave(&l2x0_lock, flags); | 240 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
230 | } | 241 | } |
231 | } | 242 | } |
232 | cache_wait(base + L2X0_CLEAN_LINE_PA, 1); | 243 | cache_wait(base + L2X0_CLEAN_LINE_PA, 1); |
233 | cache_sync(); | 244 | cache_sync(); |
234 | spin_unlock_irqrestore(&l2x0_lock, flags); | 245 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
235 | } | 246 | } |
236 | 247 | ||
237 | static void l2x0_flush_range(unsigned long start, unsigned long end) | 248 | static void l2x0_flush_range(unsigned long start, unsigned long end) |
@@ -244,7 +255,7 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
244 | return; | 255 | return; |
245 | } | 256 | } |
246 | 257 | ||
247 | spin_lock_irqsave(&l2x0_lock, flags); | 258 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
248 | start &= ~(CACHE_LINE_SIZE - 1); | 259 | start &= ~(CACHE_LINE_SIZE - 1); |
249 | while (start < end) { | 260 | while (start < end) { |
250 | unsigned long blk_end = start + min(end - start, 4096UL); | 261 | unsigned long blk_end = start + min(end - start, 4096UL); |
@@ -257,27 +268,27 @@ static void l2x0_flush_range(unsigned long start, unsigned long end) | |||
257 | debug_writel(0x00); | 268 | debug_writel(0x00); |
258 | 269 | ||
259 | if (blk_end < end) { | 270 | if (blk_end < end) { |
260 | spin_unlock_irqrestore(&l2x0_lock, flags); | 271 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
261 | spin_lock_irqsave(&l2x0_lock, flags); | 272 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
262 | } | 273 | } |
263 | } | 274 | } |
264 | cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); | 275 | cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); |
265 | cache_sync(); | 276 | cache_sync(); |
266 | spin_unlock_irqrestore(&l2x0_lock, flags); | 277 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
267 | } | 278 | } |
268 | 279 | ||
269 | static void l2x0_disable(void) | 280 | static void l2x0_disable(void) |
270 | { | 281 | { |
271 | unsigned long flags; | 282 | unsigned long flags; |
272 | 283 | ||
273 | spin_lock_irqsave(&l2x0_lock, flags); | 284 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
274 | __l2x0_flush_all(); | 285 | __l2x0_flush_all(); |
275 | writel_relaxed(0, l2x0_base + L2X0_CTRL); | 286 | writel_relaxed(0, l2x0_base + L2X0_CTRL); |
276 | dsb(); | 287 | dsb(); |
277 | spin_unlock_irqrestore(&l2x0_lock, flags); | 288 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
278 | } | 289 | } |
279 | 290 | ||
280 | static void __init l2x0_unlock(__u32 cache_id) | 291 | static void l2x0_unlock(__u32 cache_id) |
281 | { | 292 | { |
282 | int lockregs; | 293 | int lockregs; |
283 | int i; | 294 | int i; |
@@ -353,6 +364,8 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
353 | /* l2x0 controller is disabled */ | 364 | /* l2x0 controller is disabled */ |
354 | writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); | 365 | writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); |
355 | 366 | ||
367 | l2x0_saved_regs.aux_ctrl = aux; | ||
368 | |||
356 | l2x0_inv_all(); | 369 | l2x0_inv_all(); |
357 | 370 | ||
358 | /* enable L2X0 */ | 371 | /* enable L2X0 */ |
@@ -372,3 +385,202 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
372 | printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", | 385 | printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", |
373 | ways, cache_id, aux, l2x0_size); | 386 | ways, cache_id, aux, l2x0_size); |
374 | } | 387 | } |
388 | |||
389 | #ifdef CONFIG_OF | ||
390 | static void __init l2x0_of_setup(const struct device_node *np, | ||
391 | __u32 *aux_val, __u32 *aux_mask) | ||
392 | { | ||
393 | u32 data[2] = { 0, 0 }; | ||
394 | u32 tag = 0; | ||
395 | u32 dirty = 0; | ||
396 | u32 val = 0, mask = 0; | ||
397 | |||
398 | of_property_read_u32(np, "arm,tag-latency", &tag); | ||
399 | if (tag) { | ||
400 | mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; | ||
401 | val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; | ||
402 | } | ||
403 | |||
404 | of_property_read_u32_array(np, "arm,data-latency", | ||
405 | data, ARRAY_SIZE(data)); | ||
406 | if (data[0] && data[1]) { | ||
407 | mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | | ||
408 | L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; | ||
409 | val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | | ||
410 | ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); | ||
411 | } | ||
412 | |||
413 | of_property_read_u32(np, "arm,dirty-latency", &dirty); | ||
414 | if (dirty) { | ||
415 | mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; | ||
416 | val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; | ||
417 | } | ||
418 | |||
419 | *aux_val &= ~mask; | ||
420 | *aux_val |= val; | ||
421 | *aux_mask &= ~mask; | ||
422 | } | ||
423 | |||
424 | static void __init pl310_of_setup(const struct device_node *np, | ||
425 | __u32 *aux_val, __u32 *aux_mask) | ||
426 | { | ||
427 | u32 data[3] = { 0, 0, 0 }; | ||
428 | u32 tag[3] = { 0, 0, 0 }; | ||
429 | u32 filter[2] = { 0, 0 }; | ||
430 | |||
431 | of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); | ||
432 | if (tag[0] && tag[1] && tag[2]) | ||
433 | writel_relaxed( | ||
434 | ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | | ||
435 | ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | | ||
436 | ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), | ||
437 | l2x0_base + L2X0_TAG_LATENCY_CTRL); | ||
438 | |||
439 | of_property_read_u32_array(np, "arm,data-latency", | ||
440 | data, ARRAY_SIZE(data)); | ||
441 | if (data[0] && data[1] && data[2]) | ||
442 | writel_relaxed( | ||
443 | ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | | ||
444 | ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | | ||
445 | ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), | ||
446 | l2x0_base + L2X0_DATA_LATENCY_CTRL); | ||
447 | |||
448 | of_property_read_u32_array(np, "arm,filter-ranges", | ||
449 | filter, ARRAY_SIZE(filter)); | ||
450 | if (filter[1]) { | ||
451 | writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), | ||
452 | l2x0_base + L2X0_ADDR_FILTER_END); | ||
453 | writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN, | ||
454 | l2x0_base + L2X0_ADDR_FILTER_START); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | static void __init pl310_save(void) | ||
459 | { | ||
460 | u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & | ||
461 | L2X0_CACHE_ID_RTL_MASK; | ||
462 | |||
463 | l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base + | ||
464 | L2X0_TAG_LATENCY_CTRL); | ||
465 | l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base + | ||
466 | L2X0_DATA_LATENCY_CTRL); | ||
467 | l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base + | ||
468 | L2X0_ADDR_FILTER_END); | ||
469 | l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base + | ||
470 | L2X0_ADDR_FILTER_START); | ||
471 | |||
472 | if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { | ||
473 | /* | ||
474 | * From r2p0, there is Prefetch offset/control register | ||
475 | */ | ||
476 | l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base + | ||
477 | L2X0_PREFETCH_CTRL); | ||
478 | /* | ||
479 | * From r3p0, there is Power control register | ||
480 | */ | ||
481 | if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) | ||
482 | l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base + | ||
483 | L2X0_POWER_CTRL); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | static void l2x0_resume(void) | ||
488 | { | ||
489 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { | ||
490 | /* restore aux ctrl and enable l2 */ | ||
491 | l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID)); | ||
492 | |||
493 | writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base + | ||
494 | L2X0_AUX_CTRL); | ||
495 | |||
496 | l2x0_inv_all(); | ||
497 | |||
498 | writel_relaxed(1, l2x0_base + L2X0_CTRL); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static void pl310_resume(void) | ||
503 | { | ||
504 | u32 l2x0_revision; | ||
505 | |||
506 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { | ||
507 | /* restore pl310 setup */ | ||
508 | writel_relaxed(l2x0_saved_regs.tag_latency, | ||
509 | l2x0_base + L2X0_TAG_LATENCY_CTRL); | ||
510 | writel_relaxed(l2x0_saved_regs.data_latency, | ||
511 | l2x0_base + L2X0_DATA_LATENCY_CTRL); | ||
512 | writel_relaxed(l2x0_saved_regs.filter_end, | ||
513 | l2x0_base + L2X0_ADDR_FILTER_END); | ||
514 | writel_relaxed(l2x0_saved_regs.filter_start, | ||
515 | l2x0_base + L2X0_ADDR_FILTER_START); | ||
516 | |||
517 | l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & | ||
518 | L2X0_CACHE_ID_RTL_MASK; | ||
519 | |||
520 | if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { | ||
521 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, | ||
522 | l2x0_base + L2X0_PREFETCH_CTRL); | ||
523 | if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) | ||
524 | writel_relaxed(l2x0_saved_regs.pwr_ctrl, | ||
525 | l2x0_base + L2X0_POWER_CTRL); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | l2x0_resume(); | ||
530 | } | ||
531 | |||
532 | static const struct l2x0_of_data pl310_data = { | ||
533 | pl310_of_setup, | ||
534 | pl310_save, | ||
535 | pl310_resume, | ||
536 | }; | ||
537 | |||
538 | static const struct l2x0_of_data l2x0_data = { | ||
539 | l2x0_of_setup, | ||
540 | NULL, | ||
541 | l2x0_resume, | ||
542 | }; | ||
543 | |||
544 | static const struct of_device_id l2x0_ids[] __initconst = { | ||
545 | { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, | ||
546 | { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, | ||
547 | { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data }, | ||
548 | {} | ||
549 | }; | ||
550 | |||
551 | int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask) | ||
552 | { | ||
553 | struct device_node *np; | ||
554 | struct l2x0_of_data *data; | ||
555 | struct resource res; | ||
556 | |||
557 | np = of_find_matching_node(NULL, l2x0_ids); | ||
558 | if (!np) | ||
559 | return -ENODEV; | ||
560 | |||
561 | if (of_address_to_resource(np, 0, &res)) | ||
562 | return -ENODEV; | ||
563 | |||
564 | l2x0_base = ioremap(res.start, resource_size(&res)); | ||
565 | if (!l2x0_base) | ||
566 | return -ENOMEM; | ||
567 | |||
568 | l2x0_saved_regs.phy_base = res.start; | ||
569 | |||
570 | data = of_match_node(l2x0_ids, np)->data; | ||
571 | |||
572 | /* L2 configuration can only be changed if the cache is disabled */ | ||
573 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { | ||
574 | if (data->setup) | ||
575 | data->setup(np, &aux_val, &aux_mask); | ||
576 | } | ||
577 | |||
578 | if (data->save) | ||
579 | data->save(); | ||
580 | |||
581 | l2x0_init(l2x0_base, aux_val, aux_mask); | ||
582 | |||
583 | outer_cache.resume = data->resume; | ||
584 | return 0; | ||
585 | } | ||
586 | #endif | ||