xref: /plan9-contrib/sys/src/9/teg2/cache.v7.s (revision 1936bb650459bace06c38a45b60888b47e5cd459)
1/*
2 * cortex arm arch v7 cache flushing and invalidation
3 * included by l.s and rebootcode.s
4 */
5
6TEXT cacheiinv(SB), $-4				/* I invalidate */
7	MOVW	$0, R0
8	MTCP	CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall /* ok on cortex */
9	ISB
10	RET
11
12/*
13 * set/way operators, passed a suitable set/way value in R0.
14 */
15TEXT cachedwb_sw(SB), $-4
16	MTCP	CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEsi
17	RET
18
19TEXT cachedwbinv_sw(SB), $-4
20	MTCP	CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEsi
21	RET
22
23TEXT cachedinv_sw(SB), $-4
24	MTCP	CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEsi
25	RET
26
27	/* set cache size select */
28TEXT setcachelvl(SB), $-4
29	MTCP	CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0
30	ISB
31	RET
32
33	/* return cache sizes */
34TEXT getwayssets(SB), $-4
35	MFCP	CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0
36	RET
37
38/*
39 * l1 cache operations.
40 * l1 and l2 ops are intended to be called from C, thus need save no
41 * caller's regs, only those we need to preserve across calls.
42 */
43
44TEXT cachedwb(SB), $-4
45	MOVW.W	R14, -8(R13)
46	MOVW	$cachedwb_sw(SB), R0
47	MOVW	$1, R8
48	BL	wholecache(SB)
49	MOVW.P	8(R13), R15
50
51TEXT cachedwbinv(SB), $-4
52	MOVW.W	R14, -8(R13)
53	MOVW	$cachedwbinv_sw(SB), R0
54	MOVW	$1, R8
55	BL	wholecache(SB)
56	MOVW.P	8(R13), R15
57
58TEXT cachedinv(SB), $-4
59	MOVW.W	R14, -8(R13)
60	MOVW	$cachedinv_sw(SB), R0
61	MOVW	$1, R8
62	BL	wholecache(SB)
63	MOVW.P	8(R13), R15
64
65TEXT cacheuwbinv(SB), $-4
66	MOVM.DB.W [R14], (R13)	/* save lr on stack */
67	MOVW	CPSR, R1
68	CPSID			/* splhi */
69
70	MOVM.DB.W [R1], (R13)	/* save R1 on stack */
71
72	BL	cachedwbinv(SB)
73	BL	cacheiinv(SB)
74
75	MOVM.IA.W (R13), [R1]	/* restore R1 (saved CPSR) */
76	MOVW	R1, CPSR
77	MOVM.IA.W (R13), [R14]	/* restore lr */
78	RET
79
80/*
81 * architectural l2 cache operations
82 */
83
84TEXT _l2cacheuwb(SB), $-4
85	MOVW.W	R14, -8(R13)
86	MOVW	$cachedwb_sw(SB), R0
87	MOVW	$2, R8
88	BL	wholecache(SB)
89	MOVW.P	8(R13), R15	/* return */
90
91TEXT _l2cacheuwbinv(SB), $-4
92	MOVW.W	R14, -8(R13)
93	MOVW	CPSR, R1
94	CPSID			/* splhi */
95
96	MOVM.DB.W [R1], (R13)	/* save R1 on stack */
97
98	MOVW	$cachedwbinv_sw(SB), R0
99	MOVW	$2, R8
100	BL	wholecache(SB)
101
102	BL	_l2cacheuinv(SB)
103
104	MOVM.IA.W (R13), [R1]	/* restore R1 (saved CPSR) */
105	MOVW	R1, CPSR
106	MOVW.P	8(R13), R15	/* return */
107
108TEXT _l2cacheuinv(SB), $-4
109	MOVW.W	R14, -8(R13)
110	MOVW	$cachedinv_sw(SB), R0
111	MOVW	$2, R8
112	BL	wholecache(SB)
113	MOVW.P	8(R13), R15	/* return */
114
115/*
116 * callers are assumed to be the above l1 and l2 ops.
117 * R0 is the function to call in the innermost loop.
118 * R8 is the cache level (1-origin: 1 or 2).
119 *
120 * R0	func to call at entry
121 * R1	func to call after entry
122 * R2	nsets
123 * R3	way shift (computed from R8)
124 * R4	set shift (computed from R8)
125 * R5	nways
126 * R6	set scratch
127 * R7	way scratch
128 * R8	cache level, 0-origin
129 * R9	extern reg up
130 * R10	extern reg m
131 *
132 * initial translation by 5c, then massaged by hand.
133 */
134TEXT wholecache+0(SB), $-4
135	MOVW	CPSR, R2
136	MOVM.DB.W [R2,R14], (SP) /* save regs on stack */
137
138	MOVW	R0, R1		/* save argument for inner loop in R1 */
139	SUB	$1, R8		/* convert cache level to zero origin */
140
141	/* we might not have the MMU on yet, so map R1 (func) to R14's space */
142	MOVW	R14, R0		/* get R14's segment ... */
143	AND	$KSEGM, R0
144	BIC	$KSEGM,	R1	/* strip segment from func address */
145	ORR	R0, R1		/* combine them */
146
147	/* get cache sizes */
148	SLL	$1, R8, R0	/* R0 = (cache - 1) << 1 */
149	MTCP	CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0 /* set cache select */
150	ISB
151	MFCP	CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0 /* get cache sizes */
152
153	/* compute # of ways and sets for this cache level */
154	SRA	$3, R0, R5	/* R5 (ways) = R0 >> 3 */
155	AND	$((1<<10)-1), R5 /* R5 = (R0 >> 3) & MASK(10) */
156	ADD	$1, R5		/* R5 (ways) = ((R0 >> 3) & MASK(10)) + 1 */
157
158	SRA	$13, R0, R2	/* R2 = R0 >> 13 */
159	AND	$((1<<15)-1), R2 /* R2 = (R0 >> 13) & MASK(15) */
160	ADD	$1, R2		/* R2 (sets) = ((R0 >> 13) & MASK(15)) + 1 */
161
162	/* precompute set/way shifts for inner loop */
163	MOVW	$(CACHECONF+0), R3	/* +0 = l1waysh */
164	MOVW	$(CACHECONF+4), R4	/* +4 = l1setsh */
165	CMP	$0, R8		/* cache == 1? */
166	ADD.NE	$(4*2), R3	/* no, assume l2: +8 = l2waysh */
167	ADD.NE	$(4*2), R3	/* +12 = l2setsh */
168
169	MOVW	R14, R0		/* get R14's segment ... */
170	AND	$KSEGM, R0
171
172	BIC	$KSEGM,	R3	/* strip segment from address */
173	ORR	R0, R3		/* combine them */
174	BIC	$KSEGM,	R4	/* strip segment from address */
175	ORR	R0, R4		/* combine them */
176	MOVW	(R3), R3
177	MOVW	(R4), R4
178
179	CMP	$0, R3		/* sanity checks */
180	BEQ	wbuggery
181	CMP	$0, R4
182	BEQ	sbuggery
183
184	CPSID			/* splhi to make entire op atomic */
185	BARRIERS
186
187	/* iterate over ways */
188	MOVW	$0, R7		/* R7: way */
189outer:
190	/* iterate over sets */
191	MOVW	$0, R6		/* R6: set */
192inner:
193	/* compute set/way register contents */
194	SLL	R3, R7, R0 	/* R0 = way << R3 (L?WAYSH) */
195	ORR	R8<<1, R0	/* R0 = way << L?WAYSH | (cache - 1) << 1 */
196	ORR	R6<<R4, R0 	/* R0 = way<<L?WAYSH | (cache-1)<<1 |set<<R4 */
197
198	BL	(R1)		/* call set/way operation with R0 arg. */
199
200	ADD	$1, R6		/* set++ */
201	CMP	R2, R6		/* set >= sets? */
202	BLT	inner		/* no, do next set */
203
204	ADD	$1, R7		/* way++ */
205	CMP	R5, R7		/* way >= ways? */
206	BLT	outer		/* no, do next way */
207
208	MOVM.IA.W (SP), [R2,R14] /* restore regs */
209	BARRIERS
210	MOVW	R2, CPSR	/* splx */
211
212	RET
213
214wbuggery:
215	PUTC('?')
216	PUTC('c')
217	PUTC('w')
218	B	topanic
219sbuggery:
220	PUTC('?')
221	PUTC('c')
222	PUTC('s')
223topanic:
224	MOVW	$.string<>+0(SB), R0
225	BIC	$KSEGM,	R0	/* strip segment from address */
226	MOVW	R14, R1		/* get R14's segment ... */
227	AND	$KSEGM, R1
228	ORR	R1, R0		/* combine them */
229	SUB	$12, R13	/* not that it matters, since we're panicing */
230	MOVW	R14, 8(R13)
231	BL	panic(SB)	/* panic("msg %#p", LR) */
232bugloop:
233	WFI
234	B	bugloop
235
236	DATA	.string<>+0(SB)/8,$"bad cach"
237	DATA	.string<>+8(SB)/8,$"e params"
238	DATA	.string<>+16(SB)/8,$"\073 pc %\043p"
239	DATA	.string<>+24(SB)/1,$"\z"
240	GLOBL	.string<>+0(SB),$25
241