First version
[3rdparty/ote_partner/tlk.git] / arch / arm / arm / cache-l2x0.c
1 /*
2  * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 #include <sys/types.h>
25 #include <arch/arm/cache-l2x0.h>
26 #include <arch/outercache.h>
27 #include <platform/memmap.h>
28 #include <platform.h>
29 #include <debug.h>
30
31 #if ARM_WITH_L2X0
32 #define SZ_1K   1024
33 #define CACHE_LINE_SIZE         32
34
35 struct outer_cache_fns outer_cache;
36
37 static uint32_t l2x0_base;
38 static uint32_t l2x0_way_mask;  /* Bitmask of active ways */
39 static uint32_t l2x0_size;
40 static uint32_t l2x0_cache_id;
41 static uint32_t l2x0_sets;
42 static uint32_t l2x0_ways;
43
44 static inline void write_cachel2x0_reg(unsigned int data, uint32_t reg)
45 {
46         *(volatile uint32_t *)(l2x0_base + reg) = data;
47 }
48
49 static inline uint32_t read_cachel2x0_reg(uint32_t reg)
50 {
51         return *(volatile uint32_t *)(l2x0_base + reg);
52 }
53
54 static inline void l2x0_cache_wait_way(uint32_t reg, unsigned long mask)
55 {
56         /* wait for cache operation by line or way to complete */
57         while (read_cachel2x0_reg(reg) & mask)
58                 __asm__ volatile ("nop");
59 }
60
61 static void l2x0_cache_sync(void)
62 {
63         write_cachel2x0_reg(0, L2X0_CACHE_SYNC);
64         /* no cache_wait: operations by line are atomic on PL310 */
65 }
66
67 static void l2x0_flush_all(void)
68 {
69         write_cachel2x0_reg(l2x0_way_mask, L2X0_CLEAN_INV_WAY);
70         l2x0_cache_wait_way(L2X0_CLEAN_INV_WAY, l2x0_way_mask);
71         l2x0_cache_sync();
72 }
73
74 static inline void l2x0_flush_line(paddr_t addr)
75 {
76         /* no cache_wait: operations by line are atomic on PL310 */
77         write_cachel2x0_reg(addr, L2X0_CLEAN_INV_LINE_PA);
78 }
79
80 static void l2x0_flush_range(paddr_t start, size_t len)
81 {
82         paddr_t end = start + len;
83
84         if ((end - start) >= l2x0_size) {
85                 l2x0_flush_all();
86                 return;
87         }
88
89         start &= ~(CACHE_LINE_SIZE - 1);
90         while (start < end) {
91                 l2x0_flush_line(start);
92                 start += CACHE_LINE_SIZE;
93         }
94         l2x0_cache_sync();
95 }
96
97 static void l2x0_clean_all(void)
98 {
99         /* clean all ways */
100         write_cachel2x0_reg(l2x0_way_mask, L2X0_CLEAN_WAY);
101         l2x0_cache_wait_way(L2X0_CLEAN_WAY, l2x0_way_mask);
102         l2x0_cache_sync();
103 }
104
105 static inline void l2x0_clean_line(paddr_t addr)
106 {
107         /* no cache_wait: operations by line are atomic on PL310 */
108         write_cachel2x0_reg(addr, L2X0_CLEAN_LINE_PA);
109 }
110
111 static void l2x0_clean_range(paddr_t start, size_t len)
112 {
113         paddr_t end = start + len;
114
115         if (len >= l2x0_size) {
116                 l2x0_clean_all();
117                 return;
118         }
119
120         start &= ~(CACHE_LINE_SIZE - 1);
121         while (start < end) {
122                 l2x0_clean_line(start);
123                 start += CACHE_LINE_SIZE;
124         }
125         l2x0_cache_sync();
126 }
127
128 static void l2x0_inv_all(void)
129 {
130         if (read_cachel2x0_reg(L2X0_CTRL) & 1)
131                 panic("invalidating when L2 is enabled is a nono\n");
132         write_cachel2x0_reg(l2x0_way_mask, L2X0_INV_WAY);
133         l2x0_cache_wait_way(L2X0_INV_WAY, l2x0_way_mask);
134         l2x0_cache_sync();
135 }
136
137 static inline void l2x0_inv_line(paddr_t addr)
138 {
139         /* no cache_wait: operations by line are atomic on PL310 */
140         write_cachel2x0_reg(addr, L2X0_INV_LINE_PA);
141 }
142
143 static void l2x0_inv_range(paddr_t start, size_t len)
144 {
145         paddr_t end = start + len;
146
147         if (start & (CACHE_LINE_SIZE - 1)) {
148                 start &= ~(CACHE_LINE_SIZE - 1);
149                 l2x0_flush_line(start);
150                 start += CACHE_LINE_SIZE;
151         }
152
153         if (end & (CACHE_LINE_SIZE - 1)) {
154                 end &= ~(CACHE_LINE_SIZE - 1);
155                 l2x0_flush_line(end);
156         }
157
158         while (start < end) {
159                 l2x0_inv_line(start);
160                 start += CACHE_LINE_SIZE;
161         }
162         l2x0_cache_sync();
163 }
164
165 /* enables l2x0 after l2x0_disable, does not invalidate */
166 void l2x0_enable(void)
167 {
168         write_cachel2x0_reg(1, L2X0_CTRL);
169 }
170
171 static void l2x0_disable(void)
172 {
173         uint32_t enb = read_cachel2x0_reg(L2X0_CTRL);
174         write_cachel2x0_reg(enb & ~1UL, L2X0_CTRL);
175         __asm__ volatile ("dsb");
176 }
177
178 static void l2x0_unlock(uint32_t cache_id)
179 {
180         int lockregs;
181         int i;
182
183         cache_id &= L2X0_CACHE_ID_PART_MASK;
184
185         if (cache_id == L2X0_CACHE_ID_PART_L310)
186                 lockregs = 8;
187         else
188                 /* L210 and unknown types */
189                 lockregs = 1;
190
191         for (i = 0; i < lockregs; i++) {
192                 write_cachel2x0_reg(0x0, L2X0_LOCKDOWN_WAY_D_BASE +
193                         i * L2X0_LOCKDOWN_STRIDE);
194                 write_cachel2x0_reg(0x0, L2X0_LOCKDOWN_WAY_I_BASE +
195                         i * L2X0_LOCKDOWN_STRIDE);
196         }
197 }
198
199 static void l2x0_init(void)
200 {
201         if (!l2x0_base)
202                 panic("L2 cache base address undefined\n");
203
204         /* if we're already enabled then we're done */
205         if (read_cachel2x0_reg(L2X0_CTRL) & 1) {
206                 return;
207         }
208
209         l2x0_unlock(l2x0_cache_id);
210         platform_init_outer();
211         l2x0_inv_all();
212
213         l2x0_enable();
214 }
215
216 void l2x0_setup(void)
217 {
218         const char *type;
219         uint32_t aux_ctrl;
220         unsigned int waysize;
221
222         l2x0_base = platform_l2x0_base();
223         if (!l2x0_base)
224                 panic("L2 cache base address undefined\n");
225
226         l2x0_cache_id = read_cachel2x0_reg(L2X0_CACHE_ID);
227
228         aux_ctrl = read_cachel2x0_reg(L2X0_AUX_CTRL);
229         waysize = ((aux_ctrl & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17);
230         waysize = SZ_1K << (waysize + 3);
231
232         switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK)
233         {
234                 case L2X0_CACHE_ID_PART_L210:
235                         type = "L210";
236                         l2x0_ways = (aux_ctrl >> 13) & 0xf;
237                         break;
238                 case L2X0_CACHE_ID_PART_L220:
239                         type = "L220";
240                         l2x0_ways = (aux_ctrl >> 13) & 0xf;
241                         break;
242                 case L2X0_CACHE_ID_PART_L310:
243                         type = "L310";
244                         l2x0_ways = (aux_ctrl & (1 << 16)) ? 16 : 8;
245                         break;
246                 default:
247                         type = "Unknown";
248                         l2x0_ways = 0;
249                         break;
250         }
251
252         l2x0_way_mask = (1 << l2x0_ways) - 1;
253         l2x0_size = l2x0_ways * waysize;
254         l2x0_sets = waysize / CACHE_LINE_SIZE;
255
256         outer_cache.init = l2x0_init;
257         outer_cache.sync = l2x0_cache_sync;
258         outer_cache.clean_all = l2x0_clean_all;
259         outer_cache.clean_range = l2x0_clean_range;
260         outer_cache.flush_all = l2x0_flush_all;
261         outer_cache.flush_range = l2x0_flush_range;
262         outer_cache.inv_all = l2x0_inv_all;
263         outer_cache.inv_range = l2x0_inv_range;
264         outer_cache.disable = l2x0_disable;
265         outer_cache.enable = l2x0_enable;
266
267         aux_ctrl = read_cachel2x0_reg(L2X0_AUX_CTRL);
268         dprintf(SPEW, "%s cache controller enabled:\n", type);
269         dprintf(SPEW, "  %d ways, CACHE_ID 0x%x, AUX_CTRL 0x%x size = %d B\n",
270                 l2x0_ways, l2x0_cache_id, aux_ctrl, l2x0_size);
271 }
272 #endif