diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-12 11:51:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-12 11:51:56 -0500 |
commit | 42cf0f203e877cc7e502883d43b3f72149033d86 (patch) | |
tree | 3658297d62f28d7bfaa148099b08001aa9904229 /arch/arm/mm/cache-l2x0.c | |
parent | a2f0bb03f7c499e3db72c70a62b1aa5c55d6a82b (diff) | |
parent | df9ab9771c64f5229843bfe2a20fe0ee6ac59fc1 (diff) |
Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm
Pull ARM updates from Russell King:
- clang assembly fixes from Ard
- optimisations and cleanups for Aurora L2 cache support
- efficient L2 cache support for secure monitor API on Exynos SoCs
- debug menu cleanup from Daniel Thompson to allow better behaviour for
multiplatform kernels
- StrongARM SA11x0 conversion to irq domains, and pxa_timer
- kprobes updates for older ARM CPUs
- move probes support out of arch/arm/kernel to arch/arm/probes
- add inline asm support for the rbit (reverse bits) instruction
- provide an ARM mode secondary CPU entry point (for Qualcomm CPUs)
- remove the unused ARMv3 user access code
- add driver_override support to AMBA Primecell bus
* 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (55 commits)
ARM: 8256/1: driver coamba: add device binding path 'driver_override'
ARM: 8301/1: qcom: Use secondary_startup_arm()
ARM: 8302/1: Add a secondary_startup that assumes ARM mode
ARM: 8300/1: teach __asmeq that r11 == fp and r12 == ip
ARM: kprobes: Fix compilation error caused by superfluous '*'
ARM: 8297/1: cache-l2x0: optimize aurora range operations
ARM: 8296/1: cache-l2x0: clean up aurora cache handling
ARM: 8284/1: sa1100: clear RCSR_SMR on resume
ARM: 8283/1: sa1100: collie: clear PWER register on machine init
ARM: 8282/1: sa1100: use handle_domain_irq
ARM: 8281/1: sa1100: move GPIO-related IRQ code to gpio driver
ARM: 8280/1: sa1100: switch to irq_domain_add_simple()
ARM: 8279/1: sa1100: merge both GPIO irqdomains
ARM: 8278/1: sa1100: split irq handling for low GPIOs
ARM: 8291/1: replace magic number with PAGE_SHIFT macro in fixup_pv code
ARM: 8290/1: decompressor: fix a wrong comment
ARM: 8286/1: mm: Fix dma_contiguous_reserve comment
ARM: 8248/1: pm: remove outdated comment
ARM: 8274/1: Fix DEBUG_LL for multi-platform kernels (without PL01X)
ARM: 8273/1: Seperate DEBUG_UART_PHYS from DEBUG_LL on EP93XX
...
Diffstat (limited to 'arch/arm/mm/cache-l2x0.c')
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 439 |
1 files changed, 230 insertions, 209 deletions
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index c7fc009ad21c..c6c7696b8db9 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -41,12 +41,14 @@ struct l2c_init_data { | |||
41 | void (*enable)(void __iomem *, u32, unsigned); | 41 | void (*enable)(void __iomem *, u32, unsigned); |
42 | void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); | 42 | void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); |
43 | void (*save)(void __iomem *); | 43 | void (*save)(void __iomem *); |
44 | void (*configure)(void __iomem *); | ||
44 | struct outer_cache_fns outer_cache; | 45 | struct outer_cache_fns outer_cache; |
45 | }; | 46 | }; |
46 | 47 | ||
47 | #define CACHE_LINE_SIZE 32 | 48 | #define CACHE_LINE_SIZE 32 |
48 | 49 | ||
49 | static void __iomem *l2x0_base; | 50 | static void __iomem *l2x0_base; |
51 | static const struct l2c_init_data *l2x0_data; | ||
50 | static DEFINE_RAW_SPINLOCK(l2x0_lock); | 52 | static DEFINE_RAW_SPINLOCK(l2x0_lock); |
51 | static u32 l2x0_way_mask; /* Bitmask of active ways */ | 53 | static u32 l2x0_way_mask; /* Bitmask of active ways */ |
52 | static u32 l2x0_size; | 54 | static u32 l2x0_size; |
@@ -106,6 +108,19 @@ static inline void l2c_unlock(void __iomem *base, unsigned num) | |||
106 | } | 108 | } |
107 | } | 109 | } |
108 | 110 | ||
111 | static void l2c_configure(void __iomem *base) | ||
112 | { | ||
113 | if (outer_cache.configure) { | ||
114 | outer_cache.configure(&l2x0_saved_regs); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | if (l2x0_data->configure) | ||
119 | l2x0_data->configure(base); | ||
120 | |||
121 | l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL); | ||
122 | } | ||
123 | |||
109 | /* | 124 | /* |
110 | * Enable the L2 cache controller. This function must only be | 125 | * Enable the L2 cache controller. This function must only be |
111 | * called when the cache controller is known to be disabled. | 126 | * called when the cache controller is known to be disabled. |
@@ -114,7 +129,12 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
114 | { | 129 | { |
115 | unsigned long flags; | 130 | unsigned long flags; |
116 | 131 | ||
117 | l2c_write_sec(aux, base, L2X0_AUX_CTRL); | 132 | /* Do not touch the controller if already enabled. */ |
133 | if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN) | ||
134 | return; | ||
135 | |||
136 | l2x0_saved_regs.aux_ctrl = aux; | ||
137 | l2c_configure(base); | ||
118 | 138 | ||
119 | l2c_unlock(base, num_lock); | 139 | l2c_unlock(base, num_lock); |
120 | 140 | ||
@@ -136,76 +156,14 @@ static void l2c_disable(void) | |||
136 | dsb(st); | 156 | dsb(st); |
137 | } | 157 | } |
138 | 158 | ||
139 | #ifdef CONFIG_CACHE_PL310 | 159 | static void l2c_save(void __iomem *base) |
140 | static inline void cache_wait(void __iomem *reg, unsigned long mask) | ||
141 | { | ||
142 | /* cache operations by line are atomic on PL310 */ | ||
143 | } | ||
144 | #else | ||
145 | #define cache_wait l2c_wait_mask | ||
146 | #endif | ||
147 | |||
148 | static inline void cache_sync(void) | ||
149 | { | ||
150 | void __iomem *base = l2x0_base; | ||
151 | |||
152 | writel_relaxed(0, base + sync_reg_offset); | ||
153 | cache_wait(base + L2X0_CACHE_SYNC, 1); | ||
154 | } | ||
155 | |||
156 | #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) | ||
157 | static inline void debug_writel(unsigned long val) | ||
158 | { | ||
159 | l2c_set_debug(l2x0_base, val); | ||
160 | } | ||
161 | #else | ||
162 | /* Optimised out for non-errata case */ | ||
163 | static inline void debug_writel(unsigned long val) | ||
164 | { | ||
165 | } | ||
166 | #endif | ||
167 | |||
168 | static void l2x0_cache_sync(void) | ||
169 | { | ||
170 | unsigned long flags; | ||
171 | |||
172 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
173 | cache_sync(); | ||
174 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
175 | } | ||
176 | |||
177 | static void __l2x0_flush_all(void) | ||
178 | { | ||
179 | debug_writel(0x03); | ||
180 | __l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY); | ||
181 | cache_sync(); | ||
182 | debug_writel(0x00); | ||
183 | } | ||
184 | |||
185 | static void l2x0_flush_all(void) | ||
186 | { | ||
187 | unsigned long flags; | ||
188 | |||
189 | /* clean all ways */ | ||
190 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
191 | __l2x0_flush_all(); | ||
192 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
193 | } | ||
194 | |||
195 | static void l2x0_disable(void) | ||
196 | { | 160 | { |
197 | unsigned long flags; | 161 | l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); |
198 | |||
199 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
200 | __l2x0_flush_all(); | ||
201 | l2c_write_sec(0, l2x0_base, L2X0_CTRL); | ||
202 | dsb(st); | ||
203 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
204 | } | 162 | } |
205 | 163 | ||
206 | static void l2c_save(void __iomem *base) | 164 | static void l2c_resume(void) |
207 | { | 165 | { |
208 | l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); | 166 | l2c_enable(l2x0_base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock); |
209 | } | 167 | } |
210 | 168 | ||
211 | /* | 169 | /* |
@@ -288,14 +246,6 @@ static void l2c210_sync(void) | |||
288 | __l2c210_cache_sync(l2x0_base); | 246 | __l2c210_cache_sync(l2x0_base); |
289 | } | 247 | } |
290 | 248 | ||
291 | static void l2c210_resume(void) | ||
292 | { | ||
293 | void __iomem *base = l2x0_base; | ||
294 | |||
295 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) | ||
296 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1); | ||
297 | } | ||
298 | |||
299 | static const struct l2c_init_data l2c210_data __initconst = { | 249 | static const struct l2c_init_data l2c210_data __initconst = { |
300 | .type = "L2C-210", | 250 | .type = "L2C-210", |
301 | .way_size_0 = SZ_8K, | 251 | .way_size_0 = SZ_8K, |
@@ -309,7 +259,7 @@ static const struct l2c_init_data l2c210_data __initconst = { | |||
309 | .flush_all = l2c210_flush_all, | 259 | .flush_all = l2c210_flush_all, |
310 | .disable = l2c_disable, | 260 | .disable = l2c_disable, |
311 | .sync = l2c210_sync, | 261 | .sync = l2c210_sync, |
312 | .resume = l2c210_resume, | 262 | .resume = l2c_resume, |
313 | }, | 263 | }, |
314 | }; | 264 | }; |
315 | 265 | ||
@@ -466,7 +416,7 @@ static const struct l2c_init_data l2c220_data = { | |||
466 | .flush_all = l2c220_flush_all, | 416 | .flush_all = l2c220_flush_all, |
467 | .disable = l2c_disable, | 417 | .disable = l2c_disable, |
468 | .sync = l2c220_sync, | 418 | .sync = l2c220_sync, |
469 | .resume = l2c210_resume, | 419 | .resume = l2c_resume, |
470 | }, | 420 | }, |
471 | }; | 421 | }; |
472 | 422 | ||
@@ -615,39 +565,29 @@ static void __init l2c310_save(void __iomem *base) | |||
615 | L310_POWER_CTRL); | 565 | L310_POWER_CTRL); |
616 | } | 566 | } |
617 | 567 | ||
618 | static void l2c310_resume(void) | 568 | static void l2c310_configure(void __iomem *base) |
619 | { | 569 | { |
620 | void __iomem *base = l2x0_base; | 570 | unsigned revision; |
621 | 571 | ||
622 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { | 572 | /* restore pl310 setup */ |
623 | unsigned revision; | 573 | l2c_write_sec(l2x0_saved_regs.tag_latency, base, |
624 | 574 | L310_TAG_LATENCY_CTRL); | |
625 | /* restore pl310 setup */ | 575 | l2c_write_sec(l2x0_saved_regs.data_latency, base, |
626 | writel_relaxed(l2x0_saved_regs.tag_latency, | 576 | L310_DATA_LATENCY_CTRL); |
627 | base + L310_TAG_LATENCY_CTRL); | 577 | l2c_write_sec(l2x0_saved_regs.filter_end, base, |
628 | writel_relaxed(l2x0_saved_regs.data_latency, | 578 | L310_ADDR_FILTER_END); |
629 | base + L310_DATA_LATENCY_CTRL); | 579 | l2c_write_sec(l2x0_saved_regs.filter_start, base, |
630 | writel_relaxed(l2x0_saved_regs.filter_end, | 580 | L310_ADDR_FILTER_START); |
631 | base + L310_ADDR_FILTER_END); | 581 | |
632 | writel_relaxed(l2x0_saved_regs.filter_start, | 582 | revision = readl_relaxed(base + L2X0_CACHE_ID) & |
633 | base + L310_ADDR_FILTER_START); | 583 | L2X0_CACHE_ID_RTL_MASK; |
634 | 584 | ||
635 | revision = readl_relaxed(base + L2X0_CACHE_ID) & | 585 | if (revision >= L310_CACHE_ID_RTL_R2P0) |
636 | L2X0_CACHE_ID_RTL_MASK; | 586 | l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, |
637 | 587 | L310_PREFETCH_CTRL); | |
638 | if (revision >= L310_CACHE_ID_RTL_R2P0) | 588 | if (revision >= L310_CACHE_ID_RTL_R3P0) |
639 | l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, | 589 | l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, |
640 | L310_PREFETCH_CTRL); | 590 | L310_POWER_CTRL); |
641 | if (revision >= L310_CACHE_ID_RTL_R3P0) | ||
642 | l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, | ||
643 | L310_POWER_CTRL); | ||
644 | |||
645 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); | ||
646 | |||
647 | /* Re-enable full-line-of-zeros for Cortex-A9 */ | ||
648 | if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) | ||
649 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | ||
650 | } | ||
651 | } | 591 | } |
652 | 592 | ||
653 | static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) | 593 | static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) |
@@ -699,6 +639,23 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
699 | aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); | 639 | aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); |
700 | } | 640 | } |
701 | 641 | ||
642 | /* r3p0 or later has power control register */ | ||
643 | if (rev >= L310_CACHE_ID_RTL_R3P0) | ||
644 | l2x0_saved_regs.pwr_ctrl = L310_DYNAMIC_CLK_GATING_EN | | ||
645 | L310_STNDBY_MODE_EN; | ||
646 | |||
647 | /* | ||
648 | * Always enable non-secure access to the lockdown registers - | ||
649 | * we write to them as part of the L2C enable sequence so they | ||
650 | * need to be accessible. | ||
651 | */ | ||
652 | aux |= L310_AUX_CTRL_NS_LOCKDOWN; | ||
653 | |||
654 | l2c_enable(base, aux, num_lock); | ||
655 | |||
656 | /* Read back resulting AUX_CTRL value as it could have been altered. */ | ||
657 | aux = readl_relaxed(base + L2X0_AUX_CTRL); | ||
658 | |||
702 | if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { | 659 | if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { |
703 | u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); | 660 | u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); |
704 | 661 | ||
@@ -712,23 +669,12 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
712 | if (rev >= L310_CACHE_ID_RTL_R3P0) { | 669 | if (rev >= L310_CACHE_ID_RTL_R3P0) { |
713 | u32 power_ctrl; | 670 | u32 power_ctrl; |
714 | 671 | ||
715 | l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN, | ||
716 | base, L310_POWER_CTRL); | ||
717 | power_ctrl = readl_relaxed(base + L310_POWER_CTRL); | 672 | power_ctrl = readl_relaxed(base + L310_POWER_CTRL); |
718 | pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", | 673 | pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", |
719 | power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", | 674 | power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", |
720 | power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); | 675 | power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); |
721 | } | 676 | } |
722 | 677 | ||
723 | /* | ||
724 | * Always enable non-secure access to the lockdown registers - | ||
725 | * we write to them as part of the L2C enable sequence so they | ||
726 | * need to be accessible. | ||
727 | */ | ||
728 | aux |= L310_AUX_CTRL_NS_LOCKDOWN; | ||
729 | |||
730 | l2c_enable(base, aux, num_lock); | ||
731 | |||
732 | if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { | 678 | if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { |
733 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | 679 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); |
734 | cpu_notifier(l2c310_cpu_enable_flz, 0); | 680 | cpu_notifier(l2c310_cpu_enable_flz, 0); |
@@ -760,11 +706,11 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id, | |||
760 | 706 | ||
761 | if (revision >= L310_CACHE_ID_RTL_R3P0 && | 707 | if (revision >= L310_CACHE_ID_RTL_R3P0 && |
762 | revision < L310_CACHE_ID_RTL_R3P2) { | 708 | revision < L310_CACHE_ID_RTL_R3P2) { |
763 | u32 val = readl_relaxed(base + L310_PREFETCH_CTRL); | 709 | u32 val = l2x0_saved_regs.prefetch_ctrl; |
764 | /* I don't think bit23 is required here... but iMX6 does so */ | 710 | /* I don't think bit23 is required here... but iMX6 does so */ |
765 | if (val & (BIT(30) | BIT(23))) { | 711 | if (val & (BIT(30) | BIT(23))) { |
766 | val &= ~(BIT(30) | BIT(23)); | 712 | val &= ~(BIT(30) | BIT(23)); |
767 | l2c_write_sec(val, base, L310_PREFETCH_CTRL); | 713 | l2x0_saved_regs.prefetch_ctrl = val; |
768 | errata[n++] = "752271"; | 714 | errata[n++] = "752271"; |
769 | } | 715 | } |
770 | } | 716 | } |
@@ -800,6 +746,15 @@ static void l2c310_disable(void) | |||
800 | l2c_disable(); | 746 | l2c_disable(); |
801 | } | 747 | } |
802 | 748 | ||
749 | static void l2c310_resume(void) | ||
750 | { | ||
751 | l2c_resume(); | ||
752 | |||
753 | /* Re-enable full-line-of-zeros for Cortex-A9 */ | ||
754 | if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) | ||
755 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | ||
756 | } | ||
757 | |||
803 | static const struct l2c_init_data l2c310_init_fns __initconst = { | 758 | static const struct l2c_init_data l2c310_init_fns __initconst = { |
804 | .type = "L2C-310", | 759 | .type = "L2C-310", |
805 | .way_size_0 = SZ_8K, | 760 | .way_size_0 = SZ_8K, |
@@ -807,6 +762,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { | |||
807 | .enable = l2c310_enable, | 762 | .enable = l2c310_enable, |
808 | .fixup = l2c310_fixup, | 763 | .fixup = l2c310_fixup, |
809 | .save = l2c310_save, | 764 | .save = l2c310_save, |
765 | .configure = l2c310_configure, | ||
810 | .outer_cache = { | 766 | .outer_cache = { |
811 | .inv_range = l2c210_inv_range, | 767 | .inv_range = l2c210_inv_range, |
812 | .clean_range = l2c210_clean_range, | 768 | .clean_range = l2c210_clean_range, |
@@ -818,14 +774,22 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { | |||
818 | }, | 774 | }, |
819 | }; | 775 | }; |
820 | 776 | ||
821 | static void __init __l2c_init(const struct l2c_init_data *data, | 777 | static int __init __l2c_init(const struct l2c_init_data *data, |
822 | u32 aux_val, u32 aux_mask, u32 cache_id) | 778 | u32 aux_val, u32 aux_mask, u32 cache_id) |
823 | { | 779 | { |
824 | struct outer_cache_fns fns; | 780 | struct outer_cache_fns fns; |
825 | unsigned way_size_bits, ways; | 781 | unsigned way_size_bits, ways; |
826 | u32 aux, old_aux; | 782 | u32 aux, old_aux; |
827 | 783 | ||
828 | /* | 784 | /* |
785 | * Save the pointer globally so that callbacks which do not receive | ||
786 | * context from callers can access the structure. | ||
787 | */ | ||
788 | l2x0_data = kmemdup(data, sizeof(*data), GFP_KERNEL); | ||
789 | if (!l2x0_data) | ||
790 | return -ENOMEM; | ||
791 | |||
792 | /* | ||
829 | * Sanity check the aux values. aux_mask is the bits we preserve | 793 | * Sanity check the aux values. aux_mask is the bits we preserve |
830 | * from reading the hardware register, and aux_val is the bits we | 794 | * from reading the hardware register, and aux_val is the bits we |
831 | * set. | 795 | * set. |
@@ -884,6 +848,7 @@ static void __init __l2c_init(const struct l2c_init_data *data, | |||
884 | 848 | ||
885 | fns = data->outer_cache; | 849 | fns = data->outer_cache; |
886 | fns.write_sec = outer_cache.write_sec; | 850 | fns.write_sec = outer_cache.write_sec; |
851 | fns.configure = outer_cache.configure; | ||
887 | if (data->fixup) | 852 | if (data->fixup) |
888 | data->fixup(l2x0_base, cache_id, &fns); | 853 | data->fixup(l2x0_base, cache_id, &fns); |
889 | 854 | ||
@@ -910,6 +875,8 @@ static void __init __l2c_init(const struct l2c_init_data *data, | |||
910 | data->type, ways, l2x0_size >> 10); | 875 | data->type, ways, l2x0_size >> 10); |
911 | pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", | 876 | pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", |
912 | data->type, cache_id, aux); | 877 | data->type, cache_id, aux); |
878 | |||
879 | return 0; | ||
913 | } | 880 | } |
914 | 881 | ||
915 | void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) | 882 | void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) |
@@ -936,6 +903,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) | |||
936 | break; | 903 | break; |
937 | } | 904 | } |
938 | 905 | ||
906 | /* Read back current (default) hardware configuration */ | ||
907 | if (data->save) | ||
908 | data->save(l2x0_base); | ||
909 | |||
939 | __l2c_init(data, aux_val, aux_mask, cache_id); | 910 | __l2c_init(data, aux_val, aux_mask, cache_id); |
940 | } | 911 | } |
941 | 912 | ||
@@ -1102,7 +1073,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = { | |||
1102 | .flush_all = l2c210_flush_all, | 1073 | .flush_all = l2c210_flush_all, |
1103 | .disable = l2c_disable, | 1074 | .disable = l2c_disable, |
1104 | .sync = l2c210_sync, | 1075 | .sync = l2c210_sync, |
1105 | .resume = l2c210_resume, | 1076 | .resume = l2c_resume, |
1106 | }, | 1077 | }, |
1107 | }; | 1078 | }; |
1108 | 1079 | ||
@@ -1120,7 +1091,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = { | |||
1120 | .flush_all = l2c220_flush_all, | 1091 | .flush_all = l2c220_flush_all, |
1121 | .disable = l2c_disable, | 1092 | .disable = l2c_disable, |
1122 | .sync = l2c220_sync, | 1093 | .sync = l2c220_sync, |
1123 | .resume = l2c210_resume, | 1094 | .resume = l2c_resume, |
1124 | }, | 1095 | }, |
1125 | }; | 1096 | }; |
1126 | 1097 | ||
@@ -1131,32 +1102,32 @@ static void __init l2c310_of_parse(const struct device_node *np, | |||
1131 | u32 tag[3] = { 0, 0, 0 }; | 1102 | u32 tag[3] = { 0, 0, 0 }; |
1132 | u32 filter[2] = { 0, 0 }; | 1103 | u32 filter[2] = { 0, 0 }; |
1133 | u32 assoc; | 1104 | u32 assoc; |
1105 | u32 prefetch; | ||
1106 | u32 val; | ||
1134 | int ret; | 1107 | int ret; |
1135 | 1108 | ||
1136 | of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); | 1109 | of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); |
1137 | if (tag[0] && tag[1] && tag[2]) | 1110 | if (tag[0] && tag[1] && tag[2]) |
1138 | writel_relaxed( | 1111 | l2x0_saved_regs.tag_latency = |
1139 | L310_LATENCY_CTRL_RD(tag[0] - 1) | | 1112 | L310_LATENCY_CTRL_RD(tag[0] - 1) | |
1140 | L310_LATENCY_CTRL_WR(tag[1] - 1) | | 1113 | L310_LATENCY_CTRL_WR(tag[1] - 1) | |
1141 | L310_LATENCY_CTRL_SETUP(tag[2] - 1), | 1114 | L310_LATENCY_CTRL_SETUP(tag[2] - 1); |
1142 | l2x0_base + L310_TAG_LATENCY_CTRL); | ||
1143 | 1115 | ||
1144 | of_property_read_u32_array(np, "arm,data-latency", | 1116 | of_property_read_u32_array(np, "arm,data-latency", |
1145 | data, ARRAY_SIZE(data)); | 1117 | data, ARRAY_SIZE(data)); |
1146 | if (data[0] && data[1] && data[2]) | 1118 | if (data[0] && data[1] && data[2]) |
1147 | writel_relaxed( | 1119 | l2x0_saved_regs.data_latency = |
1148 | L310_LATENCY_CTRL_RD(data[0] - 1) | | 1120 | L310_LATENCY_CTRL_RD(data[0] - 1) | |
1149 | L310_LATENCY_CTRL_WR(data[1] - 1) | | 1121 | L310_LATENCY_CTRL_WR(data[1] - 1) | |
1150 | L310_LATENCY_CTRL_SETUP(data[2] - 1), | 1122 | L310_LATENCY_CTRL_SETUP(data[2] - 1); |
1151 | l2x0_base + L310_DATA_LATENCY_CTRL); | ||
1152 | 1123 | ||
1153 | of_property_read_u32_array(np, "arm,filter-ranges", | 1124 | of_property_read_u32_array(np, "arm,filter-ranges", |
1154 | filter, ARRAY_SIZE(filter)); | 1125 | filter, ARRAY_SIZE(filter)); |
1155 | if (filter[1]) { | 1126 | if (filter[1]) { |
1156 | writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), | 1127 | l2x0_saved_regs.filter_end = |
1157 | l2x0_base + L310_ADDR_FILTER_END); | 1128 | ALIGN(filter[0] + filter[1], SZ_1M); |
1158 | writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN, | 1129 | l2x0_saved_regs.filter_start = (filter[0] & ~(SZ_1M - 1)) |
1159 | l2x0_base + L310_ADDR_FILTER_START); | 1130 | | L310_ADDR_FILTER_EN; |
1160 | } | 1131 | } |
1161 | 1132 | ||
1162 | ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K); | 1133 | ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K); |
@@ -1178,6 +1149,58 @@ static void __init l2c310_of_parse(const struct device_node *np, | |||
1178 | assoc); | 1149 | assoc); |
1179 | break; | 1150 | break; |
1180 | } | 1151 | } |
1152 | |||
1153 | prefetch = l2x0_saved_regs.prefetch_ctrl; | ||
1154 | |||
1155 | ret = of_property_read_u32(np, "arm,double-linefill", &val); | ||
1156 | if (ret == 0) { | ||
1157 | if (val) | ||
1158 | prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL; | ||
1159 | else | ||
1160 | prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL; | ||
1161 | } else if (ret != -EINVAL) { | ||
1162 | pr_err("L2C-310 OF arm,double-linefill property value is missing\n"); | ||
1163 | } | ||
1164 | |||
1165 | ret = of_property_read_u32(np, "arm,double-linefill-incr", &val); | ||
1166 | if (ret == 0) { | ||
1167 | if (val) | ||
1168 | prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_INCR; | ||
1169 | else | ||
1170 | prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_INCR; | ||
1171 | } else if (ret != -EINVAL) { | ||
1172 | pr_err("L2C-310 OF arm,double-linefill-incr property value is missing\n"); | ||
1173 | } | ||
1174 | |||
1175 | ret = of_property_read_u32(np, "arm,double-linefill-wrap", &val); | ||
1176 | if (ret == 0) { | ||
1177 | if (!val) | ||
1178 | prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP; | ||
1179 | else | ||
1180 | prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP; | ||
1181 | } else if (ret != -EINVAL) { | ||
1182 | pr_err("L2C-310 OF arm,double-linefill-wrap property value is missing\n"); | ||
1183 | } | ||
1184 | |||
1185 | ret = of_property_read_u32(np, "arm,prefetch-drop", &val); | ||
1186 | if (ret == 0) { | ||
1187 | if (val) | ||
1188 | prefetch |= L310_PREFETCH_CTRL_PREFETCH_DROP; | ||
1189 | else | ||
1190 | prefetch &= ~L310_PREFETCH_CTRL_PREFETCH_DROP; | ||
1191 | } else if (ret != -EINVAL) { | ||
1192 | pr_err("L2C-310 OF arm,prefetch-drop property value is missing\n"); | ||
1193 | } | ||
1194 | |||
1195 | ret = of_property_read_u32(np, "arm,prefetch-offset", &val); | ||
1196 | if (ret == 0) { | ||
1197 | prefetch &= ~L310_PREFETCH_CTRL_OFFSET_MASK; | ||
1198 | prefetch |= val & L310_PREFETCH_CTRL_OFFSET_MASK; | ||
1199 | } else if (ret != -EINVAL) { | ||
1200 | pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n"); | ||
1201 | } | ||
1202 | |||
1203 | l2x0_saved_regs.prefetch_ctrl = prefetch; | ||
1181 | } | 1204 | } |
1182 | 1205 | ||
1183 | static const struct l2c_init_data of_l2c310_data __initconst = { | 1206 | static const struct l2c_init_data of_l2c310_data __initconst = { |
@@ -1188,6 +1211,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = { | |||
1188 | .enable = l2c310_enable, | 1211 | .enable = l2c310_enable, |
1189 | .fixup = l2c310_fixup, | 1212 | .fixup = l2c310_fixup, |
1190 | .save = l2c310_save, | 1213 | .save = l2c310_save, |
1214 | .configure = l2c310_configure, | ||
1191 | .outer_cache = { | 1215 | .outer_cache = { |
1192 | .inv_range = l2c210_inv_range, | 1216 | .inv_range = l2c210_inv_range, |
1193 | .clean_range = l2c210_clean_range, | 1217 | .clean_range = l2c210_clean_range, |
@@ -1216,6 +1240,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { | |||
1216 | .enable = l2c310_enable, | 1240 | .enable = l2c310_enable, |
1217 | .fixup = l2c310_fixup, | 1241 | .fixup = l2c310_fixup, |
1218 | .save = l2c310_save, | 1242 | .save = l2c310_save, |
1243 | .configure = l2c310_configure, | ||
1219 | .outer_cache = { | 1244 | .outer_cache = { |
1220 | .inv_range = l2c210_inv_range, | 1245 | .inv_range = l2c210_inv_range, |
1221 | .clean_range = l2c210_clean_range, | 1246 | .clean_range = l2c210_clean_range, |
@@ -1231,7 +1256,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { | |||
1231 | * noninclusive, while the hardware cache range operations use | 1256 | * noninclusive, while the hardware cache range operations use |
1232 | * inclusive start and end addresses. | 1257 | * inclusive start and end addresses. |
1233 | */ | 1258 | */ |
1234 | static unsigned long calc_range_end(unsigned long start, unsigned long end) | 1259 | static unsigned long aurora_range_end(unsigned long start, unsigned long end) |
1235 | { | 1260 | { |
1236 | /* | 1261 | /* |
1237 | * Limit the number of cache lines processed at once, | 1262 | * Limit the number of cache lines processed at once, |
@@ -1250,25 +1275,13 @@ static unsigned long calc_range_end(unsigned long start, unsigned long end) | |||
1250 | return end; | 1275 | return end; |
1251 | } | 1276 | } |
1252 | 1277 | ||
1253 | /* | ||
1254 | * Make sure 'start' and 'end' reference the same page, as L2 is PIPT | ||
1255 | * and range operations only do a TLB lookup on the start address. | ||
1256 | */ | ||
1257 | static void aurora_pa_range(unsigned long start, unsigned long end, | 1278 | static void aurora_pa_range(unsigned long start, unsigned long end, |
1258 | unsigned long offset) | 1279 | unsigned long offset) |
1259 | { | 1280 | { |
1281 | void __iomem *base = l2x0_base; | ||
1282 | unsigned long range_end; | ||
1260 | unsigned long flags; | 1283 | unsigned long flags; |
1261 | 1284 | ||
1262 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
1263 | writel_relaxed(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG); | ||
1264 | writel_relaxed(end, l2x0_base + offset); | ||
1265 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1266 | |||
1267 | cache_sync(); | ||
1268 | } | ||
1269 | |||
1270 | static void aurora_inv_range(unsigned long start, unsigned long end) | ||
1271 | { | ||
1272 | /* | 1285 | /* |
1273 | * round start and end adresses up to cache line size | 1286 | * round start and end adresses up to cache line size |
1274 | */ | 1287 | */ |
@@ -1276,15 +1289,24 @@ static void aurora_inv_range(unsigned long start, unsigned long end) | |||
1276 | end = ALIGN(end, CACHE_LINE_SIZE); | 1289 | end = ALIGN(end, CACHE_LINE_SIZE); |
1277 | 1290 | ||
1278 | /* | 1291 | /* |
1279 | * Invalidate all full cache lines between 'start' and 'end'. | 1292 | * perform operation on all full cache lines between 'start' and 'end' |
1280 | */ | 1293 | */ |
1281 | while (start < end) { | 1294 | while (start < end) { |
1282 | unsigned long range_end = calc_range_end(start, end); | 1295 | range_end = aurora_range_end(start, end); |
1283 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | 1296 | |
1284 | AURORA_INVAL_RANGE_REG); | 1297 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
1298 | writel_relaxed(start, base + AURORA_RANGE_BASE_ADDR_REG); | ||
1299 | writel_relaxed(range_end - CACHE_LINE_SIZE, base + offset); | ||
1300 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1301 | |||
1302 | writel_relaxed(0, base + AURORA_SYNC_REG); | ||
1285 | start = range_end; | 1303 | start = range_end; |
1286 | } | 1304 | } |
1287 | } | 1305 | } |
1306 | static void aurora_inv_range(unsigned long start, unsigned long end) | ||
1307 | { | ||
1308 | aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG); | ||
1309 | } | ||
1288 | 1310 | ||
1289 | static void aurora_clean_range(unsigned long start, unsigned long end) | 1311 | static void aurora_clean_range(unsigned long start, unsigned long end) |
1290 | { | 1312 | { |
@@ -1292,52 +1314,53 @@ static void aurora_clean_range(unsigned long start, unsigned long end) | |||
1292 | * If L2 is forced to WT, the L2 will always be clean and we | 1314 | * If L2 is forced to WT, the L2 will always be clean and we |
1293 | * don't need to do anything here. | 1315 | * don't need to do anything here. |
1294 | */ | 1316 | */ |
1295 | if (!l2_wt_override) { | 1317 | if (!l2_wt_override) |
1296 | start &= ~(CACHE_LINE_SIZE - 1); | 1318 | aurora_pa_range(start, end, AURORA_CLEAN_RANGE_REG); |
1297 | end = ALIGN(end, CACHE_LINE_SIZE); | ||
1298 | while (start != end) { | ||
1299 | unsigned long range_end = calc_range_end(start, end); | ||
1300 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | ||
1301 | AURORA_CLEAN_RANGE_REG); | ||
1302 | start = range_end; | ||
1303 | } | ||
1304 | } | ||
1305 | } | 1319 | } |
1306 | 1320 | ||
1307 | static void aurora_flush_range(unsigned long start, unsigned long end) | 1321 | static void aurora_flush_range(unsigned long start, unsigned long end) |
1308 | { | 1322 | { |
1309 | start &= ~(CACHE_LINE_SIZE - 1); | 1323 | if (l2_wt_override) |
1310 | end = ALIGN(end, CACHE_LINE_SIZE); | 1324 | aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG); |
1311 | while (start != end) { | 1325 | else |
1312 | unsigned long range_end = calc_range_end(start, end); | 1326 | aurora_pa_range(start, end, AURORA_FLUSH_RANGE_REG); |
1313 | /* | ||
1314 | * If L2 is forced to WT, the L2 will always be clean and we | ||
1315 | * just need to invalidate. | ||
1316 | */ | ||
1317 | if (l2_wt_override) | ||
1318 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | ||
1319 | AURORA_INVAL_RANGE_REG); | ||
1320 | else | ||
1321 | aurora_pa_range(start, range_end - CACHE_LINE_SIZE, | ||
1322 | AURORA_FLUSH_RANGE_REG); | ||
1323 | start = range_end; | ||
1324 | } | ||
1325 | } | 1327 | } |
1326 | 1328 | ||
1327 | static void aurora_save(void __iomem *base) | 1329 | static void aurora_flush_all(void) |
1328 | { | 1330 | { |
1329 | l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); | 1331 | void __iomem *base = l2x0_base; |
1330 | l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); | 1332 | unsigned long flags; |
1333 | |||
1334 | /* clean all ways */ | ||
1335 | raw_spin_lock_irqsave(&l2x0_lock, flags); | ||
1336 | __l2c_op_way(base + L2X0_CLEAN_INV_WAY); | ||
1337 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1338 | |||
1339 | writel_relaxed(0, base + AURORA_SYNC_REG); | ||
1331 | } | 1340 | } |
1332 | 1341 | ||
1333 | static void aurora_resume(void) | 1342 | static void aurora_cache_sync(void) |
1343 | { | ||
1344 | writel_relaxed(0, l2x0_base + AURORA_SYNC_REG); | ||
1345 | } | ||
1346 | |||
1347 | static void aurora_disable(void) | ||
1334 | { | 1348 | { |
1335 | void __iomem *base = l2x0_base; | 1349 | void __iomem *base = l2x0_base; |
1350 | unsigned long flags; | ||
1336 | 1351 | ||
1337 | if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) { | 1352 | raw_spin_lock_irqsave(&l2x0_lock, flags); |
1338 | writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL); | 1353 | __l2c_op_way(base + L2X0_CLEAN_INV_WAY); |
1339 | writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL); | 1354 | writel_relaxed(0, base + AURORA_SYNC_REG); |
1340 | } | 1355 | l2c_write_sec(0, base, L2X0_CTRL); |
1356 | dsb(st); | ||
1357 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | ||
1358 | } | ||
1359 | |||
1360 | static void aurora_save(void __iomem *base) | ||
1361 | { | ||
1362 | l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); | ||
1363 | l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); | ||
1341 | } | 1364 | } |
1342 | 1365 | ||
1343 | /* | 1366 | /* |
@@ -1398,10 +1421,10 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = { | |||
1398 | .inv_range = aurora_inv_range, | 1421 | .inv_range = aurora_inv_range, |
1399 | .clean_range = aurora_clean_range, | 1422 | .clean_range = aurora_clean_range, |
1400 | .flush_range = aurora_flush_range, | 1423 | .flush_range = aurora_flush_range, |
1401 | .flush_all = l2x0_flush_all, | 1424 | .flush_all = aurora_flush_all, |
1402 | .disable = l2x0_disable, | 1425 | .disable = aurora_disable, |
1403 | .sync = l2x0_cache_sync, | 1426 | .sync = aurora_cache_sync, |
1404 | .resume = aurora_resume, | 1427 | .resume = l2c_resume, |
1405 | }, | 1428 | }, |
1406 | }; | 1429 | }; |
1407 | 1430 | ||
@@ -1414,7 +1437,7 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = { | |||
1414 | .fixup = aurora_fixup, | 1437 | .fixup = aurora_fixup, |
1415 | .save = aurora_save, | 1438 | .save = aurora_save, |
1416 | .outer_cache = { | 1439 | .outer_cache = { |
1417 | .resume = aurora_resume, | 1440 | .resume = l2c_resume, |
1418 | }, | 1441 | }, |
1419 | }; | 1442 | }; |
1420 | 1443 | ||
@@ -1562,6 +1585,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = { | |||
1562 | .of_parse = l2c310_of_parse, | 1585 | .of_parse = l2c310_of_parse, |
1563 | .enable = l2c310_enable, | 1586 | .enable = l2c310_enable, |
1564 | .save = l2c310_save, | 1587 | .save = l2c310_save, |
1588 | .configure = l2c310_configure, | ||
1565 | .outer_cache = { | 1589 | .outer_cache = { |
1566 | .inv_range = bcm_inv_range, | 1590 | .inv_range = bcm_inv_range, |
1567 | .clean_range = bcm_clean_range, | 1591 | .clean_range = bcm_clean_range, |
@@ -1583,18 +1607,12 @@ static void __init tauros3_save(void __iomem *base) | |||
1583 | readl_relaxed(base + L310_PREFETCH_CTRL); | 1607 | readl_relaxed(base + L310_PREFETCH_CTRL); |
1584 | } | 1608 | } |
1585 | 1609 | ||
1586 | static void tauros3_resume(void) | 1610 | static void tauros3_configure(void __iomem *base) |
1587 | { | 1611 | { |
1588 | void __iomem *base = l2x0_base; | 1612 | writel_relaxed(l2x0_saved_regs.aux2_ctrl, |
1589 | 1613 | base + TAUROS3_AUX2_CTRL); | |
1590 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { | 1614 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, |
1591 | writel_relaxed(l2x0_saved_regs.aux2_ctrl, | 1615 | base + L310_PREFETCH_CTRL); |
1592 | base + TAUROS3_AUX2_CTRL); | ||
1593 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, | ||
1594 | base + L310_PREFETCH_CTRL); | ||
1595 | |||
1596 | l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); | ||
1597 | } | ||
1598 | } | 1616 | } |
1599 | 1617 | ||
1600 | static const struct l2c_init_data of_tauros3_data __initconst = { | 1618 | static const struct l2c_init_data of_tauros3_data __initconst = { |
@@ -1603,9 +1621,10 @@ static const struct l2c_init_data of_tauros3_data __initconst = { | |||
1603 | .num_lock = 8, | 1621 | .num_lock = 8, |
1604 | .enable = l2c_enable, | 1622 | .enable = l2c_enable, |
1605 | .save = tauros3_save, | 1623 | .save = tauros3_save, |
1624 | .configure = tauros3_configure, | ||
1606 | /* Tauros3 broadcasts L1 cache operations to L2 */ | 1625 | /* Tauros3 broadcasts L1 cache operations to L2 */ |
1607 | .outer_cache = { | 1626 | .outer_cache = { |
1608 | .resume = tauros3_resume, | 1627 | .resume = l2c_resume, |
1609 | }, | 1628 | }, |
1610 | }; | 1629 | }; |
1611 | 1630 | ||
@@ -1661,6 +1680,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) | |||
1661 | if (!of_property_read_bool(np, "cache-unified")) | 1680 | if (!of_property_read_bool(np, "cache-unified")) |
1662 | pr_err("L2C: device tree omits to specify unified cache\n"); | 1681 | pr_err("L2C: device tree omits to specify unified cache\n"); |
1663 | 1682 | ||
1683 | /* Read back current (default) hardware configuration */ | ||
1684 | if (data->save) | ||
1685 | data->save(l2x0_base); | ||
1686 | |||
1664 | /* L2 configuration can only be changed if the cache is disabled */ | 1687 | /* L2 configuration can only be changed if the cache is disabled */ |
1665 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) | 1688 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) |
1666 | if (data->of_parse) | 1689 | if (data->of_parse) |
@@ -1671,8 +1694,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) | |||
1671 | else | 1694 | else |
1672 | cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); | 1695 | cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); |
1673 | 1696 | ||
1674 | __l2c_init(data, aux_val, aux_mask, cache_id); | 1697 | return __l2c_init(data, aux_val, aux_mask, cache_id); |
1675 | |||
1676 | return 0; | ||
1677 | } | 1698 | } |
1678 | #endif | 1699 | #endif |