1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
|
/* $OpenBSD: arml2cc.c,v 1.4 2015/05/20 00:39:16 jsg Exp $ */
/*
* Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/evcount.h>
#include <sys/socket.h>
#include <sys/timeout.h>
#include <machine/intr.h>
#include <machine/bus.h>
#include <arm/cpufunc.h>
#include <arm/cortex/cortex.h>
#include <arm/cortex/smc.h>
#define PL310_ERRATA_727915
/* offset from periphbase */
#define L2C_ADDR 0x2000
#define L2C_SIZE 0x1000
/* registers */
#define L2C_CACHE_ID 0x000
#define L2C_CACHE_TYPE 0x004
#define L2C_CTL 0x100
#define L2C_AUXCTL 0x104
#define L2C_TAG_RAM_CTL 0x108
#define L2C_DATA_RAM_CTL 0x10c
#define L2C_EVC_CTR_CTL 0x200
#define L2C_EVC_CTR0_CTL 0x204
#define L2C_EVC_CTR1_CTL 0x208
#define L2C_EVC_CTR0_VAL 0x20c
#define L2C_EVC_CTR1_VAL 0x210
#define L2C_INT_MASK 0x214
#define L2C_INT_MASK_STS 0x218
#define L2C_INT_RAW_STS 0x21c
#define L2C_INT_CLR 0x220
#define L2C_CACHE_SYNC 0x730
#define L2C_INV_PA 0x770
#define L2C_INV_WAY 0x77c
#define L2C_CLEAN_PA 0x7b0
#define L2C_CLEAN_INDEX 0x7b8
#define L2C_CLEAN_WAY 0x7bc
#define L2C_CLEAN_INV_PA 0x7f0
#define L2C_CLEAN_INV_INDEX 0x7f8
#define L2C_CLEAN_INV_WAY 0x7fc
#define L2C_D_LOCKDOWN0 0x900
#define L2C_I_LOCKDOWN0 0x904
#define L2C_D_LOCKDOWN1 0x908
#define L2C_I_LOCKDOWN1 0x90c
#define L2C_D_LOCKDOWN2 0x910
#define L2C_I_LOCKDOWN2 0x914
#define L2C_D_LOCKDOWN3 0x918
#define L2C_I_LOCKDOWN3 0x91c
#define L2C_D_LOCKDOWN4 0x920
#define L2C_I_LOCKDOWN4 0x924
#define L2C_D_LOCKDOWN5 0x928
#define L2C_I_LOCKDOWN5 0x92c
#define L2C_D_LOCKDOWN6 0x930
#define L2C_I_LOCKDOWN6 0x934
#define L2C_D_LOCKDOWN7 0x938
#define L2C_I_LOCKDOWN7 0x93c
#define L2C_LOCKDOWN_LINE_EN 0x950
#define L2C_UNLOCK_WAY 0x954
#define L2C_ADDR_FILTER_START 0xc00
#define L2C_ADDR_FILTER_END 0xc04
#define L2C_DEBUG_CTL 0xf40
#define L2C_PREFETCH_CTL 0xf60
#define L2C_POWER_CTL 0xf80
#define L2C_CACHE_ID_RELEASE_MASK 0x3f
#define L2C_CACHE_TYPE_LINESIZE 0x3
#define L2C_AUXCTL_ASSOC_SHIFT 16
#define L2C_AUXCTL_ASSOC_MASK 0x1
#define roundup2(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
struct arml2cc_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
uint32_t sc_enabled;
uint32_t sc_waymask;
uint32_t sc_dcache_line_size;
};
struct arml2cc_softc *arml2cc_sc;
int arml2cc_match(struct device *, void *, void *);
void arml2cc_attach(struct device *parent, struct device *self, void *args);
void arml2cc_enable(struct arml2cc_softc *);
void arml2cc_disable(struct arml2cc_softc *);
void arml2cc_sdcache_wbinv_all(void);
void arml2cc_sdcache_wbinv_range(vaddr_t, paddr_t, psize_t);
void arml2cc_sdcache_inv_range(vaddr_t, paddr_t, psize_t);
void arml2cc_sdcache_wb_range(vaddr_t, paddr_t, psize_t);
void arml2cc_cache_range_op(paddr_t, psize_t, bus_size_t);
void arml2cc_cache_way_op(struct arml2cc_softc *, bus_size_t, uint32_t);
void arml2cc_cache_op(struct arml2cc_softc *, bus_size_t, uint32_t);
void arml2cc_cache_sync(struct arml2cc_softc *);
struct cfattach armliicc_ca = {
sizeof (struct arml2cc_softc), arml2cc_match, arml2cc_attach
};
struct cfdriver armliicc_cd = {
NULL, "armliicc", DV_DULL
};
int
arml2cc_match(struct device *parent, void *cfdata, void *aux)
{
if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9)
return (1);
return (0);
}
void
arml2cc_attach(struct device *parent, struct device *self, void *args)
{
struct cortex_attach_args *ia = args;
struct arml2cc_softc *sc = (struct arml2cc_softc *) self;
sc->sc_iot = ia->ca_iot;
if (bus_space_map(sc->sc_iot, ia->ca_periphbase + L2C_ADDR,
L2C_SIZE, 0, &sc->sc_ioh))
panic("arml2cc_attach: bus_space_map failed!");
printf(": rtl %d", bus_space_read_4(sc->sc_iot, sc->sc_ioh,
L2C_CACHE_ID) & 0x3f);
arml2cc_sc = sc;
if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CTL))
panic("L2 Cache controller was already enabled\n");
sc->sc_dcache_line_size = 32 << (bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CACHE_TYPE) & L2C_CACHE_TYPE_LINESIZE);
sc->sc_waymask = (8 << ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_AUXCTL)
>> L2C_AUXCTL_ASSOC_SHIFT) & L2C_AUXCTL_ASSOC_MASK)) - 1;
printf(" waymask: 0x%08x\n", sc->sc_waymask);
arml2cc_enable(sc);
sc->sc_enabled = 1;
arml2cc_sdcache_wbinv_all();
cpufuncs.cf_sdcache_wbinv_all = arml2cc_sdcache_wbinv_all;
cpufuncs.cf_sdcache_wbinv_range = arml2cc_sdcache_wbinv_range;
cpufuncs.cf_sdcache_inv_range = arml2cc_sdcache_inv_range;
cpufuncs.cf_sdcache_wb_range = arml2cc_sdcache_wb_range;
}
void
arml2cc_enable(struct arml2cc_softc *sc)
{
int s;
s = splhigh();
platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_CTL, SMC_L2_CTL,
1);
arml2cc_cache_way_op(sc, L2C_INV_WAY, sc->sc_waymask);
arml2cc_cache_sync(sc);
splx(s);
}
void
arml2cc_disable(struct arml2cc_softc *sc)
{
int s;
s = splhigh();
arml2cc_cache_way_op(sc, L2C_CLEAN_INV_WAY, sc->sc_waymask);
arml2cc_cache_sync(sc);
platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_CTL, SMC_L2_CTL, 0);
splx(s);
}
void
arml2cc_cache_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t val)
{
bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off) & 1) {
/* spin */
}
}
void
arml2cc_cache_way_op(struct arml2cc_softc *sc, bus_size_t off, uint32_t way_mask)
{
bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, way_mask);
while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off) & way_mask) {
/* spin */
}
}
void
arml2cc_cache_sync(struct arml2cc_softc *sc)
{
/* ARM Errata 753970 */
bus_space_write_4(sc->sc_iot, sc->sc_ioh, 0x740, 0xffffffff);
}
void
arml2cc_cache_range_op(paddr_t pa, psize_t len, bus_size_t cache_op)
{
struct arml2cc_softc * const sc = arml2cc_sc;
size_t line_size = sc->sc_dcache_line_size;
size_t line_mask = line_size - 1;
paddr_t endpa;
endpa = pa + len;
pa = pa & ~line_mask;
// printf("l2inv op %x %08x %08x incr %d %d\n", cache_op, pa, endpa, line_size, len);
while (endpa > pa) {
arml2cc_cache_op(sc, cache_op, pa);
pa += line_size;
}
}
void
arml2cc_sdcache_wbinv_all(void)
{
struct arml2cc_softc *sc = arml2cc_sc;
if (sc == NULL || !sc->sc_enabled)
return;
#ifdef PL310_ERRATA_727915
platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3);
#endif
bus_space_write_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY, sc->sc_waymask);
while(bus_space_read_4(sc->sc_iot, sc->sc_ioh, L2C_CLEAN_INV_WAY) & sc->sc_waymask);
#ifdef PL310_ERRATA_727915
platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0);
#endif
arml2cc_cache_sync(sc);
}
void
arml2cc_sdcache_wbinv_range(vaddr_t va, paddr_t pa, psize_t len)
{
struct arml2cc_softc *sc = arml2cc_sc;
if (sc == NULL || !sc->sc_enabled)
return;
#ifdef PL310_ERRATA_727915
platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 3);
#endif
arml2cc_cache_range_op(pa, len, L2C_CLEAN_INV_PA);
arml2cc_cache_sync(sc);
#ifdef PL310_ERRATA_727915
platform_smc_write(sc->sc_iot, sc->sc_ioh, L2C_DEBUG_CTL, SMC_L2_DBG, 0);
#endif
}
void
arml2cc_sdcache_inv_range(vaddr_t va, paddr_t pa, psize_t len)
{
struct arml2cc_softc *sc = arml2cc_sc;
if (sc == NULL || !sc->sc_enabled)
return;
arml2cc_cache_range_op(pa, len, L2C_INV_PA);
arml2cc_cache_sync(sc);
}
void
arml2cc_sdcache_wb_range(vaddr_t va, paddr_t pa, psize_t len)
{
struct arml2cc_softc *sc = arml2cc_sc;
if (sc == NULL || !sc->sc_enabled)
return;
arml2cc_cache_range_op(pa, len, L2C_CLEAN_PA);
arml2cc_cache_sync(sc);
}
|