diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/hardware/cache-l2x0.h | 25 | ||||
-rw-r--r-- | arch/arm/include/asm/outercache.h | 7 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 12 | ||||
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 129 |
4 files changed, 163 insertions, 10 deletions
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h index c48cb1e1c46c..434edccdf7f3 100644 --- a/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/arch/arm/include/asm/hardware/cache-l2x0.h | |||
@@ -67,6 +67,13 @@ | |||
67 | #define L2X0_CACHE_ID_PART_MASK (0xf << 6) | 67 | #define L2X0_CACHE_ID_PART_MASK (0xf << 6) |
68 | #define L2X0_CACHE_ID_PART_L210 (1 << 6) | 68 | #define L2X0_CACHE_ID_PART_L210 (1 << 6) |
69 | #define L2X0_CACHE_ID_PART_L310 (3 << 6) | 69 | #define L2X0_CACHE_ID_PART_L310 (3 << 6) |
70 | #define L2X0_CACHE_ID_RTL_MASK 0x3f | ||
71 | #define L2X0_CACHE_ID_RTL_R0P0 0x0 | ||
72 | #define L2X0_CACHE_ID_RTL_R1P0 0x2 | ||
73 | #define L2X0_CACHE_ID_RTL_R2P0 0x4 | ||
74 | #define L2X0_CACHE_ID_RTL_R3P0 0x5 | ||
75 | #define L2X0_CACHE_ID_RTL_R3P1 0x6 | ||
76 | #define L2X0_CACHE_ID_RTL_R3P2 0x8 | ||
70 | 77 | ||
71 | #define L2X0_AUX_CTRL_MASK 0xc0000fff | 78 | #define L2X0_AUX_CTRL_MASK 0xc0000fff |
72 | #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0 | 79 | #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0 |
@@ -96,6 +103,24 @@ | |||
96 | #ifndef __ASSEMBLY__ | 103 | #ifndef __ASSEMBLY__ |
97 | extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); | 104 | extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); |
98 | extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask); | 105 | extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask); |
106 | |||
107 | struct l2x0_regs { | ||
108 | unsigned long phy_base; | ||
109 | unsigned long aux_ctrl; | ||
110 | /* | ||
111 | * Whether the following registers need to be saved/restored | ||
112 | * depends on platform | ||
113 | */ | ||
114 | unsigned long tag_latency; | ||
115 | unsigned long data_latency; | ||
116 | unsigned long filter_start; | ||
117 | unsigned long filter_end; | ||
118 | unsigned long prefetch_ctrl; | ||
119 | unsigned long pwr_ctrl; | ||
120 | }; | ||
121 | |||
122 | extern struct l2x0_regs l2x0_saved_regs; | ||
123 | |||
99 | #endif | 124 | #endif |
100 | 125 | ||
101 | #endif | 126 | #endif |
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index d8387437ec5a..53426c66352a 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h | |||
@@ -34,6 +34,7 @@ struct outer_cache_fns { | |||
34 | void (*sync)(void); | 34 | void (*sync)(void); |
35 | #endif | 35 | #endif |
36 | void (*set_debug)(unsigned long); | 36 | void (*set_debug)(unsigned long); |
37 | void (*resume)(void); | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | #ifdef CONFIG_OUTER_CACHE | 40 | #ifdef CONFIG_OUTER_CACHE |
@@ -74,6 +75,12 @@ static inline void outer_disable(void) | |||
74 | outer_cache.disable(); | 75 | outer_cache.disable(); |
75 | } | 76 | } |
76 | 77 | ||
78 | static inline void outer_resume(void) | ||
79 | { | ||
80 | if (outer_cache.resume) | ||
81 | outer_cache.resume(); | ||
82 | } | ||
83 | |||
77 | #else | 84 | #else |
78 | 85 | ||
79 | static inline void outer_inv_range(phys_addr_t start, phys_addr_t end) | 86 | static inline void outer_inv_range(phys_addr_t start, phys_addr_t end) |
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 16baba2e4369..1429d8989fb9 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/thread_info.h> | 20 | #include <asm/thread_info.h> |
21 | #include <asm/memory.h> | 21 | #include <asm/memory.h> |
22 | #include <asm/procinfo.h> | 22 | #include <asm/procinfo.h> |
23 | #include <asm/hardware/cache-l2x0.h> | ||
23 | #include <linux/kbuild.h> | 24 | #include <linux/kbuild.h> |
24 | 25 | ||
25 | /* | 26 | /* |
@@ -92,6 +93,17 @@ int main(void) | |||
92 | DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); | 93 | DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); |
93 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); | 94 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); |
94 | BLANK(); | 95 | BLANK(); |
96 | #ifdef CONFIG_CACHE_L2X0 | ||
97 | DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base)); | ||
98 | DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl)); | ||
99 | DEFINE(L2X0_R_TAG_LATENCY, offsetof(struct l2x0_regs, tag_latency)); | ||
100 | DEFINE(L2X0_R_DATA_LATENCY, offsetof(struct l2x0_regs, data_latency)); | ||
101 | DEFINE(L2X0_R_FILTER_START, offsetof(struct l2x0_regs, filter_start)); | ||
102 | DEFINE(L2X0_R_FILTER_END, offsetof(struct l2x0_regs, filter_end)); | ||
103 | DEFINE(L2X0_R_PREFETCH_CTRL, offsetof(struct l2x0_regs, prefetch_ctrl)); | ||
104 | DEFINE(L2X0_R_PWR_CTRL, offsetof(struct l2x0_regs, pwr_ctrl)); | ||
105 | BLANK(); | ||
106 | #endif | ||
95 | #ifdef CONFIG_CPU_HAS_ASID | 107 | #ifdef CONFIG_CPU_HAS_ASID |
96 | DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id)); | 108 | DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id)); |
97 | BLANK(); | 109 | BLANK(); |
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 0d85d221d7b0..3f9b9980478e 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -33,6 +33,14 @@ static DEFINE_SPINLOCK(l2x0_lock); | |||
33 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ | 33 | static uint32_t l2x0_way_mask; /* Bitmask of active ways */ |
34 | static uint32_t l2x0_size; | 34 | static uint32_t l2x0_size; |
35 | 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 | |||
36 | 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) |
37 | { | 45 | { |
38 | /* wait for cache operation by line or way to complete */ | 46 | /* wait for cache operation by line or way to complete */ |
@@ -280,7 +288,7 @@ static void l2x0_disable(void) | |||
280 | spin_unlock_irqrestore(&l2x0_lock, flags); | 288 | spin_unlock_irqrestore(&l2x0_lock, flags); |
281 | } | 289 | } |
282 | 290 | ||
283 | static void __init l2x0_unlock(__u32 cache_id) | 291 | static void l2x0_unlock(__u32 cache_id) |
284 | { | 292 | { |
285 | int lockregs; | 293 | int lockregs; |
286 | int i; | 294 | int i; |
@@ -356,6 +364,8 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask) | |||
356 | /* l2x0 controller is disabled */ | 364 | /* l2x0 controller is disabled */ |
357 | writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); | 365 | writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); |
358 | 366 | ||
367 | l2x0_saved_regs.aux_ctrl = aux; | ||
368 | |||
359 | l2x0_inv_all(); | 369 | l2x0_inv_all(); |
360 | 370 | ||
361 | /* enable L2X0 */ | 371 | /* enable L2X0 */ |
@@ -445,33 +455,132 @@ static void __init pl310_of_setup(const struct device_node *np, | |||
445 | } | 455 | } |
446 | } | 456 | } |
447 | 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 | |||
448 | static const struct of_device_id l2x0_ids[] __initconst = { | 544 | static const struct of_device_id l2x0_ids[] __initconst = { |
449 | { .compatible = "arm,pl310-cache", .data = pl310_of_setup }, | 545 | { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, |
450 | { .compatible = "arm,l220-cache", .data = l2x0_of_setup }, | 546 | { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, |
451 | { .compatible = "arm,l210-cache", .data = l2x0_of_setup }, | 547 | { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data }, |
452 | {} | 548 | {} |
453 | }; | 549 | }; |
454 | 550 | ||
455 | int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask) | 551 | int __init l2x0_of_init(__u32 aux_val, __u32 aux_mask) |
456 | { | 552 | { |
457 | struct device_node *np; | 553 | struct device_node *np; |
458 | void (*l2_setup)(const struct device_node *np, | 554 | struct l2x0_of_data *data; |
459 | __u32 *aux_val, __u32 *aux_mask); | 555 | struct resource res; |
460 | 556 | ||
461 | np = of_find_matching_node(NULL, l2x0_ids); | 557 | np = of_find_matching_node(NULL, l2x0_ids); |
462 | if (!np) | 558 | if (!np) |
463 | return -ENODEV; | 559 | return -ENODEV; |
464 | l2x0_base = of_iomap(np, 0); | 560 | |
561 | if (of_address_to_resource(np, 0, &res)) | ||
562 | return -ENODEV; | ||
563 | |||
564 | l2x0_base = ioremap(res.start, resource_size(&res)); | ||
465 | if (!l2x0_base) | 565 | if (!l2x0_base) |
466 | return -ENOMEM; | 566 | return -ENOMEM; |
467 | 567 | ||
568 | l2x0_saved_regs.phy_base = res.start; | ||
569 | |||
570 | data = of_match_node(l2x0_ids, np)->data; | ||
571 | |||
468 | /* L2 configuration can only be changed if the cache is disabled */ | 572 | /* L2 configuration can only be changed if the cache is disabled */ |
469 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { | 573 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) { |
470 | l2_setup = of_match_node(l2x0_ids, np)->data; | 574 | if (data->setup) |
471 | if (l2_setup) | 575 | data->setup(np, &aux_val, &aux_mask); |
472 | l2_setup(np, &aux_val, &aux_mask); | ||
473 | } | 576 | } |
577 | |||
578 | if (data->save) | ||
579 | data->save(); | ||
580 | |||
474 | l2x0_init(l2x0_base, aux_val, aux_mask); | 581 | l2x0_init(l2x0_base, aux_val, aux_mask); |
582 | |||
583 | outer_cache.resume = data->resume; | ||
475 | return 0; | 584 | return 0; |
476 | } | 585 | } |
477 | #endif | 586 | #endif |