xref: /openbmc/linux/arch/arm/mm/proc-feroceon.S (revision 4a1fd556)
1/*
2 *  linux/arch/arm/mm/proc-feroceon.S: MMU functions for Feroceon
3 *
4 *  Heavily based on proc-arm926.S
5 *  Maintainer: Assaf Hoffman <hoffman@marvell.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22#include <linux/linkage.h>
23#include <linux/init.h>
24#include <asm/assembler.h>
25#include <asm/elf.h>
26#include <asm/pgtable-hwdef.h>
27#include <asm/pgtable.h>
28#include <asm/page.h>
29#include <asm/ptrace.h>
30#include "proc-macros.S"
31
32/*
33 * This is the maximum size of an area which will be invalidated
34 * using the single invalidate entry instructions.  Anything larger
35 * than this, and we go for the whole cache.
36 *
37 * This value should be chosen such that we choose the cheapest
38 * alternative.
39 */
40#define CACHE_DLIMIT	16384
41
42/*
43 * the cache line size of the I and D cache
44 */
45#define CACHE_DLINESIZE	32
46
47	.text
48/*
49 * cpu_feroceon_proc_init()
50 */
51ENTRY(cpu_feroceon_proc_init)
52	mov	pc, lr
53
54/*
55 * cpu_feroceon_proc_fin()
56 */
57ENTRY(cpu_feroceon_proc_fin)
58	stmfd	sp!, {lr}
59	mov	ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
60	msr	cpsr_c, ip
61	bl	feroceon_flush_kern_cache_all
62	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
63	bic	r0, r0, #0x1000			@ ...i............
64	bic	r0, r0, #0x000e			@ ............wca.
65	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
66	ldmfd	sp!, {pc}
67
68/*
69 * cpu_feroceon_reset(loc)
70 *
71 * Perform a soft reset of the system.  Put the CPU into the
72 * same state as it would be if it had been reset, and branch
73 * to what would be the reset vector.
74 *
75 * loc: location to jump to for soft reset
76 */
77	.align	5
78ENTRY(cpu_feroceon_reset)
79	mov	ip, #0
80	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
81	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
82#ifdef CONFIG_MMU
83	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
84#endif
85	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
86	bic	ip, ip, #0x000f			@ ............wcam
87	bic	ip, ip, #0x1100			@ ...i...s........
88	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
89	mov	pc, r0
90
91/*
92 * cpu_feroceon_do_idle()
93 *
94 * Called with IRQs disabled
95 */
96	.align	10
97ENTRY(cpu_feroceon_do_idle)
98	mov	r0, #0
99	mcr	p15, 0, r0, c7, c10, 4		@ Drain write buffer
100	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
101	mov	pc, lr
102
103/*
104 *	flush_user_cache_all()
105 *
106 *	Clean and invalidate all cache entries in a particular
107 *	address space.
108 */
109ENTRY(feroceon_flush_user_cache_all)
110	/* FALLTHROUGH */
111
112/*
113 *	flush_kern_cache_all()
114 *
115 *	Clean and invalidate the entire cache.
116 */
117ENTRY(feroceon_flush_kern_cache_all)
118	mov	r2, #VM_EXEC
119	mov	ip, #0
120__flush_whole_cache:
121#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
122	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
123#else
1241:	mrc	p15, 0, r15, c7, c14, 3 	@ test,clean,invalidate
125	bne	1b
126#endif
127	tst	r2, #VM_EXEC
128	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
129	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
130	mov	pc, lr
131
132/*
133 *	flush_user_cache_range(start, end, flags)
134 *
135 *	Clean and invalidate a range of cache entries in the
136 *	specified address range.
137 *
138 *	- start	- start address (inclusive)
139 *	- end	- end address (exclusive)
140 *	- flags	- vm_flags describing address space
141 */
142ENTRY(feroceon_flush_user_cache_range)
143	mov	ip, #0
144	sub	r3, r1, r0			@ calculate total size
145	cmp	r3, #CACHE_DLIMIT
146	bgt	__flush_whole_cache
1471:	tst	r2, #VM_EXEC
148#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
149	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
150	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
151	add	r0, r0, #CACHE_DLINESIZE
152	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
153	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
154	add	r0, r0, #CACHE_DLINESIZE
155#else
156	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
157	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
158	add	r0, r0, #CACHE_DLINESIZE
159	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
160	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
161	add	r0, r0, #CACHE_DLINESIZE
162#endif
163	cmp	r0, r1
164	blo	1b
165	tst	r2, #VM_EXEC
166	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
167	mov	pc, lr
168
169/*
170 *	coherent_kern_range(start, end)
171 *
172 *	Ensure coherency between the Icache and the Dcache in the
173 *	region described by start, end.  If you have non-snooping
174 *	Harvard caches, you need to implement this function.
175 *
176 *	- start	- virtual start address
177 *	- end	- virtual end address
178 */
179ENTRY(feroceon_coherent_kern_range)
180	/* FALLTHROUGH */
181
182/*
183 *	coherent_user_range(start, end)
184 *
185 *	Ensure coherency between the Icache and the Dcache in the
186 *	region described by start, end.  If you have non-snooping
187 *	Harvard caches, you need to implement this function.
188 *
189 *	- start	- virtual start address
190 *	- end	- virtual end address
191 */
192ENTRY(feroceon_coherent_user_range)
193	bic	r0, r0, #CACHE_DLINESIZE - 1
1941:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
195	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
196	add	r0, r0, #CACHE_DLINESIZE
197	cmp	r0, r1
198	blo	1b
199	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
200	mov	pc, lr
201
202/*
203 *	flush_kern_dcache_page(void *page)
204 *
205 *	Ensure no D cache aliasing occurs, either with itself or
206 *	the I cache
207 *
208 *	- addr	- page aligned address
209 */
210ENTRY(feroceon_flush_kern_dcache_page)
211	add	r1, r0, #PAGE_SZ
2121:	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
213	add	r0, r0, #CACHE_DLINESIZE
214	cmp	r0, r1
215	blo	1b
216	mov	r0, #0
217	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
218	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
219	mov	pc, lr
220
221/*
222 *	dma_inv_range(start, end)
223 *
224 *	Invalidate (discard) the specified virtual address range.
225 *	May not write back any entries.  If 'start' or 'end'
226 *	are not cache line aligned, those lines must be written
227 *	back.
228 *
229 *	- start	- virtual start address
230 *	- end	- virtual end address
231 *
232 * (same as v4wb)
233 */
234ENTRY(feroceon_dma_inv_range)
235#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
236	tst	r0, #CACHE_DLINESIZE - 1
237	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
238	tst	r1, #CACHE_DLINESIZE - 1
239	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
240#endif
241	bic	r0, r0, #CACHE_DLINESIZE - 1
2421:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
243	add	r0, r0, #CACHE_DLINESIZE
244	cmp	r0, r1
245	blo	1b
246	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
247	mov	pc, lr
248
249/*
250 *	dma_clean_range(start, end)
251 *
252 *	Clean the specified virtual address range.
253 *
254 *	- start	- virtual start address
255 *	- end	- virtual end address
256 *
257 * (same as v4wb)
258 */
259ENTRY(feroceon_dma_clean_range)
260#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
261	bic	r0, r0, #CACHE_DLINESIZE - 1
2621:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
263	add	r0, r0, #CACHE_DLINESIZE
264	cmp	r0, r1
265	blo	1b
266#endif
267	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
268	mov	pc, lr
269
270/*
271 *	dma_flush_range(start, end)
272 *
273 *	Clean and invalidate the specified virtual address range.
274 *
275 *	- start	- virtual start address
276 *	- end	- virtual end address
277 */
278ENTRY(feroceon_dma_flush_range)
279	bic	r0, r0, #CACHE_DLINESIZE - 1
2801:
281#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
282	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
283#else
284	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
285#endif
286	add	r0, r0, #CACHE_DLINESIZE
287	cmp	r0, r1
288	blo	1b
289	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
290	mov	pc, lr
291
292ENTRY(feroceon_cache_fns)
293	.long	feroceon_flush_kern_cache_all
294	.long	feroceon_flush_user_cache_all
295	.long	feroceon_flush_user_cache_range
296	.long	feroceon_coherent_kern_range
297	.long	feroceon_coherent_user_range
298	.long	feroceon_flush_kern_dcache_page
299	.long	feroceon_dma_inv_range
300	.long	feroceon_dma_clean_range
301	.long	feroceon_dma_flush_range
302
303ENTRY(cpu_feroceon_dcache_clean_area)
304#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
3051:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
306	add	r0, r0, #CACHE_DLINESIZE
307	subs	r1, r1, #CACHE_DLINESIZE
308	bhi	1b
309#endif
310	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
311	mov	pc, lr
312
313/* =============================== PageTable ============================== */
314
315/*
316 * cpu_feroceon_switch_mm(pgd)
317 *
318 * Set the translation base pointer to be as described by pgd.
319 *
320 * pgd: new page tables
321 */
322	.align	5
323ENTRY(cpu_feroceon_switch_mm)
324#ifdef CONFIG_MMU
325	mov	ip, #0
326#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
327	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
328#else
329@ && 'Clean & Invalidate whole DCache'
3301:	mrc	p15, 0, r15, c7, c14, 3 	@ test,clean,invalidate
331	bne	1b
332#endif
333	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
334	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
335	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
336	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
337#endif
338	mov	pc, lr
339
340/*
341 * cpu_feroceon_set_pte_ext(ptep, pte, ext)
342 *
343 * Set a PTE and flush it out
344 */
345	.align	5
346ENTRY(cpu_feroceon_set_pte_ext)
347#ifdef CONFIG_MMU
348	str	r1, [r0], #-2048		@ linux version
349
350	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
351
352	bic	r2, r1, #PTE_SMALL_AP_MASK
353	bic	r2, r2, #PTE_TYPE_MASK
354	orr	r2, r2, #PTE_TYPE_SMALL
355
356	tst	r1, #L_PTE_USER			@ User?
357	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
358
359	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
360	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
361
362	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
363	movne	r2, #0
364
365#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
366	eor	r3, r2, #0x0a			@ C & small page?
367	tst	r3, #0x0b
368	biceq	r2, r2, #4
369#endif
370	str	r2, [r0]			@ hardware version
371	mov	r0, r0
372#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
373	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
374#endif
375	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
376#endif
377	mov	pc, lr
378
379	__INIT
380
381	.type	__feroceon_setup, #function
382__feroceon_setup:
383	mov	r0, #0
384	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
385	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
386#ifdef CONFIG_MMU
387	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
388#endif
389
390
391#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
392	mov	r0, #4				@ disable write-back on caches explicitly
393	mcr	p15, 7, r0, c15, c0, 0
394#endif
395
396	adr	r5, feroceon_crval
397	ldmia	r5, {r5, r6}
398	mrc	p15, 0, r0, c1, c0		@ get control register v4
399	bic	r0, r0, r5
400	orr	r0, r0, r6
401#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
402	orr	r0, r0, #0x4000			@ .1.. .... .... ....
403#endif
404	mov	pc, lr
405	.size	__feroceon_setup, . - __feroceon_setup
406
407	/*
408	 *  R
409	 * .RVI ZFRS BLDP WCAM
410	 * .011 0001 ..11 0101
411	 *
412	 */
413	.type	feroceon_crval, #object
414feroceon_crval:
415	crval	clear=0x00007f3f, mmuset=0x00003135, ucset=0x00001134
416
417	__INITDATA
418
419/*
420 * Purpose : Function pointers used to access above functions - all calls
421 *	     come through these
422 */
423	.type	feroceon_processor_functions, #object
424feroceon_processor_functions:
425	.word	v5t_early_abort
426	.word	pabort_noifar
427	.word	cpu_feroceon_proc_init
428	.word	cpu_feroceon_proc_fin
429	.word	cpu_feroceon_reset
430	.word	cpu_feroceon_do_idle
431	.word	cpu_feroceon_dcache_clean_area
432	.word	cpu_feroceon_switch_mm
433	.word	cpu_feroceon_set_pte_ext
434	.size	feroceon_processor_functions, . - feroceon_processor_functions
435
436	.section ".rodata"
437
438	.type	cpu_arch_name, #object
439cpu_arch_name:
440	.asciz	"armv5te"
441	.size	cpu_arch_name, . - cpu_arch_name
442
443	.type	cpu_elf_name, #object
444cpu_elf_name:
445	.asciz	"v5"
446	.size	cpu_elf_name, . - cpu_elf_name
447
448	.type	cpu_feroceon_name, #object
449cpu_feroceon_name:
450	.asciz	"Feroceon"
451	.size	cpu_feroceon_name, . - cpu_feroceon_name
452
453	.align
454
455	.section ".proc.info.init", #alloc, #execinstr
456
457#ifdef CONFIG_CPU_FEROCEON_OLD_ID
458	.type	__feroceon_old_id_proc_info,#object
459__feroceon_old_id_proc_info:
460	.long	0x41069260
461	.long	0xfffffff0
462	.long   PMD_TYPE_SECT | \
463		PMD_SECT_BUFFERABLE | \
464		PMD_SECT_CACHEABLE | \
465		PMD_BIT4 | \
466		PMD_SECT_AP_WRITE | \
467		PMD_SECT_AP_READ
468	.long   PMD_TYPE_SECT | \
469		PMD_BIT4 | \
470		PMD_SECT_AP_WRITE | \
471		PMD_SECT_AP_READ
472	b	__feroceon_setup
473	.long	cpu_arch_name
474	.long	cpu_elf_name
475	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
476	.long	cpu_feroceon_name
477	.long	feroceon_processor_functions
478	.long	v4wbi_tlb_fns
479	.long	v4wb_user_fns
480	.long	feroceon_cache_fns
481	.size	__feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info
482#endif
483
484	.type	__feroceon_proc_info,#object
485__feroceon_proc_info:
486	.long	0x56055310
487	.long	0xfffffff0
488	.long   PMD_TYPE_SECT | \
489		PMD_SECT_BUFFERABLE | \
490		PMD_SECT_CACHEABLE | \
491		PMD_BIT4 | \
492		PMD_SECT_AP_WRITE | \
493		PMD_SECT_AP_READ
494	.long   PMD_TYPE_SECT | \
495		PMD_BIT4 | \
496		PMD_SECT_AP_WRITE | \
497		PMD_SECT_AP_READ
498	b	__feroceon_setup
499	.long	cpu_arch_name
500	.long	cpu_elf_name
501	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
502	.long	cpu_feroceon_name
503	.long	feroceon_processor_functions
504	.long	v4wbi_tlb_fns
505	.long	v4wb_user_fns
506	.long	feroceon_cache_fns
507	.size	__feroceon_proc_info, . - __feroceon_proc_info
508