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 <linux/kernel.h>
12 #include <asm/armv7.h>
13 #include <asm/processor.h>
15 #include "cache-uniphier.h"
18 #define UNIPHIER_SSCOQAD_IS_NEEDED(op) \
19 ((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
20 #define UNIPHIER_SSCOQWM_IS_NEEDED(op) \
21 ((op & UNIPHIER_SSCOQM_TID_MASK) == UNIPHIER_SSCOQM_TID_WAY)
23 /* uniphier_cache_sync - perform a sync point for a particular cache level */
24 static void uniphier_cache_sync(void)
26 /* drain internal buffers */
27 writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
28 /* need a read back to confirm */
29 readl(UNIPHIER_SSCOPE);
33 * uniphier_cache_maint_common - run a queue operation
35 * @start: start address of range operation (don't care for "all" operation)
36 * @size: data size of range operation (don't care for "all" operation)
37 * @ways: target ways (don't care for operations other than pre-fetch, touch
38 * @operation: flags to specify the desired cache operation
40 static void uniphier_cache_maint_common(u32 start, u32 size, u32 ways,
43 /* clear the complete notification flag */
44 writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
47 /* set cache operation */
48 writel(UNIPHIER_SSCOQM_CE | operation, UNIPHIER_SSCOQM);
50 /* set address range if needed */
51 if (likely(UNIPHIER_SSCOQAD_IS_NEEDED(operation))) {
52 writel(start, UNIPHIER_SSCOQAD);
53 writel(size, UNIPHIER_SSCOQSZ);
56 /* set target ways if needed */
57 if (unlikely(UNIPHIER_SSCOQWM_IS_NEEDED(operation)))
58 writel(ways, UNIPHIER_SSCOQWN);
59 } while (unlikely(readl(UNIPHIER_SSCOPPQSEF) &
60 (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
62 /* wait until the operation is completed */
63 while (likely(readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF))
67 static void uniphier_cache_maint_all(u32 operation)
69 uniphier_cache_maint_common(0, 0, 0, UNIPHIER_SSCOQM_S_ALL | operation);
71 uniphier_cache_sync();
74 static void uniphier_cache_maint_range(u32 start, u32 end, u32 ways,
80 * If the start address is not aligned,
81 * perform a cache operation for the first cache-line
83 start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
87 if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
88 /* this means cache operation for all range */
89 uniphier_cache_maint_all(operation);
94 * If the end address is not aligned,
95 * perform a cache operation for the last cache-line
97 size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
100 u32 chunk_size = min_t(u32, size, UNIPHIER_SSC_RANGE_OP_MAX_SIZE);
102 uniphier_cache_maint_common(start, chunk_size, ways,
103 UNIPHIER_SSCOQM_S_RANGE | operation);
109 uniphier_cache_sync();
112 void uniphier_cache_prefetch_range(u32 start, u32 end, u32 ways)
114 uniphier_cache_maint_range(start, end, ways,
115 UNIPHIER_SSCOQM_TID_WAY |
116 UNIPHIER_SSCOQM_CM_PREFETCH);
119 void uniphier_cache_touch_range(u32 start, u32 end, u32 ways)
121 uniphier_cache_maint_range(start, end, ways,
122 UNIPHIER_SSCOQM_TID_WAY |
123 UNIPHIER_SSCOQM_CM_TOUCH);
126 void uniphier_cache_touch_zero_range(u32 start, u32 end, u32 ways)
128 uniphier_cache_maint_range(start, end, ways,
129 UNIPHIER_SSCOQM_TID_WAY |
130 UNIPHIER_SSCOQM_CM_TOUCH_ZERO);
133 #ifdef CONFIG_UNIPHIER_L2CACHE_ON
134 void v7_outer_cache_flush_all(void)
136 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
139 void v7_outer_cache_inval_all(void)
141 uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
144 void v7_outer_cache_flush_range(u32 start, u32 end)
146 uniphier_cache_maint_range(start, end, 0, UNIPHIER_SSCOQM_CM_FLUSH);
149 void v7_outer_cache_inval_range(u32 start, u32 end)
151 if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
152 start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
153 uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE, 0,
154 UNIPHIER_SSCOQM_CM_FLUSH);
155 start += UNIPHIER_SSC_LINE_SIZE;
159 uniphier_cache_sync();
163 if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
164 end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
165 uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE, 0,
166 UNIPHIER_SSCOQM_CM_FLUSH);
170 uniphier_cache_sync();
174 uniphier_cache_maint_range(start, end, 0, UNIPHIER_SSCOQM_CM_INV);
177 void v7_outer_cache_enable(void)
181 writel(U32_MAX, UNIPHIER_SSCLPDAWCR); /* activate all ways */
182 tmp = readl(UNIPHIER_SSCC);
183 tmp |= UNIPHIER_SSCC_ON;
184 writel(tmp, UNIPHIER_SSCC);
187 void v7_outer_cache_disable(void)
191 tmp = readl(UNIPHIER_SSCC);
192 tmp &= ~UNIPHIER_SSCC_ON;
193 writel(tmp, UNIPHIER_SSCC);
197 void enable_caches(void)