2 * Copyright (C) 2012-2014 Panasonic Corporation
3 * Copyright (C) 2015-2016 Socionext Inc.
4 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
6 * SPDX-License-Identifier: GPL-2.0+
11 #include <asm/armv7.h>
15 #ifdef CONFIG_UNIPHIER_L2CACHE_ON
16 static void uniphier_cache_sync(void)
18 /* drain internal buffers */
19 writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
20 /* need a read back to confirm */
21 readl(UNIPHIER_SSCOPE);
24 static void uniphier_cache_maint_all(u32 operation)
26 /* clear the complete notification flag */
27 writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
29 /* try until the command is successfully set */
31 writel(UNIPHIER_SSCOQM_S_ALL | UNIPHIER_SSCOQM_CE | operation,
33 } while (readl(UNIPHIER_SSCOPPQSEF) &
34 (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE));
36 /* wait until the operation is completed */
37 while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF)
40 uniphier_cache_sync();
43 void v7_outer_cache_flush_all(void)
45 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
48 void v7_outer_cache_inval_all(void)
50 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
53 static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation)
55 /* clear the complete notification flag */
56 writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
58 /* try until the command is successfully set */
60 writel(UNIPHIER_SSCOQM_S_RANGE | UNIPHIER_SSCOQM_CE | operation,
62 writel(start, UNIPHIER_SSCOQAD);
63 writel(size, UNIPHIER_SSCOQSZ);
65 } while (readl(UNIPHIER_SSCOPPQSEF) &
66 (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE));
68 /* wait until the operation is completed */
69 while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF)
73 static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
78 * If start address is not aligned to cache-line,
79 * do cache operation for the first cache-line
81 start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
85 if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
86 /* this means cache operation for all range */
87 uniphier_cache_maint_all(operation);
92 * If end address is not aligned to cache-line,
93 * do cache operation for the last cache-line
95 size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
98 u32 chunk_size = size > UNIPHIER_SSC_RANGE_OP_MAX_SIZE ?
99 UNIPHIER_SSC_RANGE_OP_MAX_SIZE : size;
100 __uniphier_cache_maint_range(start, chunk_size, operation);
106 uniphier_cache_sync();
109 void v7_outer_cache_flush_range(u32 start, u32 end)
111 uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
114 void v7_outer_cache_inval_range(u32 start, u32 end)
116 if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
117 start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
118 __uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE,
119 UNIPHIER_SSCOQM_CM_FLUSH);
120 start += UNIPHIER_SSC_LINE_SIZE;
124 uniphier_cache_sync();
128 if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
129 end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
130 __uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE,
131 UNIPHIER_SSCOQM_CM_FLUSH);
135 uniphier_cache_sync();
139 uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV);
142 void v7_outer_cache_enable(void)
146 writel(U32_MAX, UNIPHIER_SSCLPDAWCR); /* activate all ways */
147 tmp = readl(UNIPHIER_SSCC);
148 tmp |= UNIPHIER_SSCC_ON;
149 writel(tmp, UNIPHIER_SSCC);
153 void v7_outer_cache_disable(void)
157 tmp = readl(UNIPHIER_SSCC);
158 tmp &= ~UNIPHIER_SSCC_ON;
159 writel(tmp, UNIPHIER_SSCC);
162 void enable_caches(void)