aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig13
-rw-r--r--arch/arm/mm/cache-l2x0.c36
2 files changed, 49 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 762ae536f909..0f1ad743ccdd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -924,6 +924,19 @@ config ARM_ERRATA_460075
924 ACTLR register. Note that setting specific bits in the ACTLR register 924 ACTLR register. Note that setting specific bits in the ACTLR register
925 may not be available in non-secure mode. 925 may not be available in non-secure mode.
926 926
927config PL310_ERRATA_588369
928 bool "Clean & Invalidate maintenance operations do not invalidate clean lines"
929 depends on CACHE_L2X0 && ARCH_OMAP4
930 help
931 The PL310 L2 cache controller implements three types of Clean &
932 Invalidate maintenance operations: by Physical Address
933 (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC).
934 They are architecturally defined to behave as the execution of a
935 clean operation followed immediately by an invalidate operation,
936 both performing to the same memory location. This functionality
937 is not correctly implemented in PL310 as clean lines are not
938 invalidated as a result of these operations. Note that this errata
939 uses Texas Instrument's secure monitor api.
927endmenu 940endmenu
928 941
929source "arch/arm/common/Kconfig" 942source "arch/arm/common/Kconfig"
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 1a14d18e5713..07334632d3e2 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -56,12 +56,42 @@ static inline void l2x0_inv_line(unsigned long addr)
56 writel(addr, base + L2X0_INV_LINE_PA); 56 writel(addr, base + L2X0_INV_LINE_PA);
57} 57}
58 58
59#ifdef CONFIG_PL310_ERRATA_588369
60static void debug_writel(unsigned long val)
61{
62 extern void omap_smc1(u32 fn, u32 arg);
63
64 /*
65 * Texas Instrument secure monitor api to modify the
66 * PL310 Debug Control Register.
67 */
68 omap_smc1(0x100, val);
69}
70
71static inline void l2x0_flush_line(unsigned long addr)
72{
73 void __iomem *base = l2x0_base;
74
75 /* Clean by PA followed by Invalidate by PA */
76 cache_wait(base + L2X0_CLEAN_LINE_PA, 1);
77 writel(addr, base + L2X0_CLEAN_LINE_PA);
78 cache_wait(base + L2X0_INV_LINE_PA, 1);
79 writel(addr, base + L2X0_INV_LINE_PA);
80}
81#else
82
83/* Optimised out for non-errata case */
84static inline void debug_writel(unsigned long val)
85{
86}
87
59static inline void l2x0_flush_line(unsigned long addr) 88static inline void l2x0_flush_line(unsigned long addr)
60{ 89{
61 void __iomem *base = l2x0_base; 90 void __iomem *base = l2x0_base;
62 cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); 91 cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1);
63 writel(addr, base + L2X0_CLEAN_INV_LINE_PA); 92 writel(addr, base + L2X0_CLEAN_INV_LINE_PA);
64} 93}
94#endif
65 95
66static inline void l2x0_inv_all(void) 96static inline void l2x0_inv_all(void)
67{ 97{
@@ -83,13 +113,17 @@ static void l2x0_inv_range(unsigned long start, unsigned long end)
83 spin_lock_irqsave(&l2x0_lock, flags); 113 spin_lock_irqsave(&l2x0_lock, flags);
84 if (start & (CACHE_LINE_SIZE - 1)) { 114 if (start & (CACHE_LINE_SIZE - 1)) {
85 start &= ~(CACHE_LINE_SIZE - 1); 115 start &= ~(CACHE_LINE_SIZE - 1);
116 debug_writel(0x03);
86 l2x0_flush_line(start); 117 l2x0_flush_line(start);
118 debug_writel(0x00);
87 start += CACHE_LINE_SIZE; 119 start += CACHE_LINE_SIZE;
88 } 120 }
89 121
90 if (end & (CACHE_LINE_SIZE - 1)) { 122 if (end & (CACHE_LINE_SIZE - 1)) {
91 end &= ~(CACHE_LINE_SIZE - 1); 123 end &= ~(CACHE_LINE_SIZE - 1);
124 debug_writel(0x03);
92 l2x0_flush_line(end); 125 l2x0_flush_line(end);
126 debug_writel(0x00);
93 } 127 }
94 128
95 while (start < end) { 129 while (start < end) {
@@ -145,10 +179,12 @@ static void l2x0_flush_range(unsigned long start, unsigned long end)
145 while (start < end) { 179 while (start < end) {
146 unsigned long blk_end = start + min(end - start, 4096UL); 180 unsigned long blk_end = start + min(end - start, 4096UL);
147 181
182 debug_writel(0x03);
148 while (start < blk_end) { 183 while (start < blk_end) {
149 l2x0_flush_line(start); 184 l2x0_flush_line(start);
150 start += CACHE_LINE_SIZE; 185 start += CACHE_LINE_SIZE;
151 } 186 }
187 debug_writel(0x00);
152 188
153 if (blk_end < end) { 189 if (blk_end < end) {
154 spin_unlock_irqrestore(&l2x0_lock, flags); 190 spin_unlock_irqrestore(&l2x0_lock, flags);