xref: /OK3568_Linux_fs/kernel/arch/arm/mm/proc-v6.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun *  linux/arch/arm/mm/proc-v6.S
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun *  Copyright (C) 2001 Deep Blue Solutions Ltd.
6*4882a593Smuzhiyun *  Modified by Catalin Marinas for noMMU support
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun *  This is the "shell" of the ARMv6 processor support.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun#include <linux/init.h>
11*4882a593Smuzhiyun#include <linux/linkage.h>
12*4882a593Smuzhiyun#include <linux/pgtable.h>
13*4882a593Smuzhiyun#include <asm/assembler.h>
14*4882a593Smuzhiyun#include <asm/asm-offsets.h>
15*4882a593Smuzhiyun#include <asm/hwcap.h>
16*4882a593Smuzhiyun#include <asm/pgtable-hwdef.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun#include "proc-macros.S"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun#define D_CACHE_LINE_SIZE	32
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun#define TTB_C		(1 << 0)
23*4882a593Smuzhiyun#define TTB_S		(1 << 1)
24*4882a593Smuzhiyun#define TTB_IMP		(1 << 2)
25*4882a593Smuzhiyun#define TTB_RGN_NC	(0 << 3)
26*4882a593Smuzhiyun#define TTB_RGN_WBWA	(1 << 3)
27*4882a593Smuzhiyun#define TTB_RGN_WT	(2 << 3)
28*4882a593Smuzhiyun#define TTB_RGN_WB	(3 << 3)
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun#define TTB_FLAGS_UP	TTB_RGN_WBWA
31*4882a593Smuzhiyun#define PMD_FLAGS_UP	PMD_SECT_WB
32*4882a593Smuzhiyun#define TTB_FLAGS_SMP	TTB_RGN_WBWA|TTB_S
33*4882a593Smuzhiyun#define PMD_FLAGS_SMP	PMD_SECT_WBWA|PMD_SECT_S
34*4882a593Smuzhiyun
35*4882a593SmuzhiyunENTRY(cpu_v6_proc_init)
36*4882a593Smuzhiyun	ret	lr
37*4882a593Smuzhiyun
38*4882a593SmuzhiyunENTRY(cpu_v6_proc_fin)
39*4882a593Smuzhiyun	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
40*4882a593Smuzhiyun	bic	r0, r0, #0x1000			@ ...i............
41*4882a593Smuzhiyun	bic	r0, r0, #0x0006			@ .............ca.
42*4882a593Smuzhiyun	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
43*4882a593Smuzhiyun	ret	lr
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun/*
46*4882a593Smuzhiyun *	cpu_v6_reset(loc)
47*4882a593Smuzhiyun *
48*4882a593Smuzhiyun *	Perform a soft reset of the system.  Put the CPU into the
49*4882a593Smuzhiyun *	same state as it would be if it had been reset, and branch
50*4882a593Smuzhiyun *	to what would be the reset vector.
51*4882a593Smuzhiyun *
52*4882a593Smuzhiyun *	- loc   - location to jump to for soft reset
53*4882a593Smuzhiyun */
54*4882a593Smuzhiyun	.align	5
55*4882a593Smuzhiyun	.pushsection	.idmap.text, "ax"
56*4882a593SmuzhiyunENTRY(cpu_v6_reset)
57*4882a593Smuzhiyun	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
58*4882a593Smuzhiyun	bic	r1, r1, #0x1			@ ...............m
59*4882a593Smuzhiyun	mcr	p15, 0, r1, c1, c0, 0		@ disable MMU
60*4882a593Smuzhiyun	mov	r1, #0
61*4882a593Smuzhiyun	mcr	p15, 0, r1, c7, c5, 4		@ ISB
62*4882a593Smuzhiyun	ret	r0
63*4882a593SmuzhiyunENDPROC(cpu_v6_reset)
64*4882a593Smuzhiyun	.popsection
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun/*
67*4882a593Smuzhiyun *	cpu_v6_do_idle()
68*4882a593Smuzhiyun *
69*4882a593Smuzhiyun *	Idle the processor (eg, wait for interrupt).
70*4882a593Smuzhiyun *
71*4882a593Smuzhiyun *	IRQs are already disabled.
72*4882a593Smuzhiyun */
73*4882a593SmuzhiyunENTRY(cpu_v6_do_idle)
74*4882a593Smuzhiyun	mov	r1, #0
75*4882a593Smuzhiyun	mcr	p15, 0, r1, c7, c10, 4		@ DWB - WFI may enter a low-power mode
76*4882a593Smuzhiyun	mcr	p15, 0, r1, c7, c0, 4		@ wait for interrupt
77*4882a593Smuzhiyun	ret	lr
78*4882a593Smuzhiyun
79*4882a593SmuzhiyunENTRY(cpu_v6_dcache_clean_area)
80*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
81*4882a593Smuzhiyun	add	r0, r0, #D_CACHE_LINE_SIZE
82*4882a593Smuzhiyun	subs	r1, r1, #D_CACHE_LINE_SIZE
83*4882a593Smuzhiyun	bhi	1b
84*4882a593Smuzhiyun	ret	lr
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun/*
87*4882a593Smuzhiyun *	cpu_v6_switch_mm(pgd_phys, tsk)
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun *	Set the translation table base pointer to be pgd_phys
90*4882a593Smuzhiyun *
91*4882a593Smuzhiyun *	- pgd_phys - physical address of new TTB
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun *	It is assumed that:
94*4882a593Smuzhiyun *	- we are not using split page tables
95*4882a593Smuzhiyun */
96*4882a593SmuzhiyunENTRY(cpu_v6_switch_mm)
97*4882a593Smuzhiyun#ifdef CONFIG_MMU
98*4882a593Smuzhiyun	mov	r2, #0
99*4882a593Smuzhiyun	mmid	r1, r1				@ get mm->context.id
100*4882a593Smuzhiyun	ALT_SMP(orr	r0, r0, #TTB_FLAGS_SMP)
101*4882a593Smuzhiyun	ALT_UP(orr	r0, r0, #TTB_FLAGS_UP)
102*4882a593Smuzhiyun	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
103*4882a593Smuzhiyun	mcr	p15, 0, r2, c7, c10, 4		@ drain write buffer
104*4882a593Smuzhiyun	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
105*4882a593Smuzhiyun#ifdef CONFIG_PID_IN_CONTEXTIDR
106*4882a593Smuzhiyun	mrc	p15, 0, r2, c13, c0, 1		@ read current context ID
107*4882a593Smuzhiyun	bic	r2, r2, #0xff			@ extract the PID
108*4882a593Smuzhiyun	and	r1, r1, #0xff
109*4882a593Smuzhiyun	orr	r1, r1, r2			@ insert into new context ID
110*4882a593Smuzhiyun#endif
111*4882a593Smuzhiyun	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
112*4882a593Smuzhiyun#endif
113*4882a593Smuzhiyun	ret	lr
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun/*
116*4882a593Smuzhiyun *	cpu_v6_set_pte_ext(ptep, pte, ext)
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun *	Set a level 2 translation table entry.
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun *	- ptep  - pointer to level 2 translation table entry
121*4882a593Smuzhiyun *		  (hardware version is stored at -1024 bytes)
122*4882a593Smuzhiyun *	- pte   - PTE value to store
123*4882a593Smuzhiyun *	- ext	- value for extended PTE bits
124*4882a593Smuzhiyun */
125*4882a593Smuzhiyun	armv6_mt_table cpu_v6
126*4882a593Smuzhiyun
127*4882a593SmuzhiyunENTRY(cpu_v6_set_pte_ext)
128*4882a593Smuzhiyun#ifdef CONFIG_MMU
129*4882a593Smuzhiyun	armv6_set_pte_ext cpu_v6
130*4882a593Smuzhiyun#endif
131*4882a593Smuzhiyun	ret	lr
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun/* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
134*4882a593Smuzhiyun.globl	cpu_v6_suspend_size
135*4882a593Smuzhiyun.equ	cpu_v6_suspend_size, 4 * 6
136*4882a593Smuzhiyun#ifdef CONFIG_ARM_CPU_SUSPEND
137*4882a593SmuzhiyunENTRY(cpu_v6_do_suspend)
138*4882a593Smuzhiyun	stmfd	sp!, {r4 - r9, lr}
139*4882a593Smuzhiyun	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
140*4882a593Smuzhiyun#ifdef CONFIG_MMU
141*4882a593Smuzhiyun	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
142*4882a593Smuzhiyun	mrc	p15, 0, r6, c2, c0, 1	@ Translation table base 1
143*4882a593Smuzhiyun#endif
144*4882a593Smuzhiyun	mrc	p15, 0, r7, c1, c0, 1	@ auxiliary control register
145*4882a593Smuzhiyun	mrc	p15, 0, r8, c1, c0, 2	@ co-processor access control
146*4882a593Smuzhiyun	mrc	p15, 0, r9, c1, c0, 0	@ control register
147*4882a593Smuzhiyun	stmia	r0, {r4 - r9}
148*4882a593Smuzhiyun	ldmfd	sp!, {r4- r9, pc}
149*4882a593SmuzhiyunENDPROC(cpu_v6_do_suspend)
150*4882a593Smuzhiyun
151*4882a593SmuzhiyunENTRY(cpu_v6_do_resume)
152*4882a593Smuzhiyun	mov	ip, #0
153*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c14, 0	@ clean+invalidate D cache
154*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
155*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c15, 0	@ clean+invalidate cache
156*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c10, 4	@ drain write buffer
157*4882a593Smuzhiyun	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
158*4882a593Smuzhiyun	ldmia	r0, {r4 - r9}
159*4882a593Smuzhiyun	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
160*4882a593Smuzhiyun#ifdef CONFIG_MMU
161*4882a593Smuzhiyun	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
162*4882a593Smuzhiyun	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
163*4882a593Smuzhiyun	ALT_UP(orr	r1, r1, #TTB_FLAGS_UP)
164*4882a593Smuzhiyun	mcr	p15, 0, r1, c2, c0, 0	@ Translation table base 0
165*4882a593Smuzhiyun	mcr	p15, 0, r6, c2, c0, 1	@ Translation table base 1
166*4882a593Smuzhiyun	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
167*4882a593Smuzhiyun#endif
168*4882a593Smuzhiyun	mcr	p15, 0, r7, c1, c0, 1	@ auxiliary control register
169*4882a593Smuzhiyun	mcr	p15, 0, r8, c1, c0, 2	@ co-processor access control
170*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c5, 4	@ ISB
171*4882a593Smuzhiyun	mov	r0, r9			@ control register
172*4882a593Smuzhiyun	b	cpu_resume_mmu
173*4882a593SmuzhiyunENDPROC(cpu_v6_do_resume)
174*4882a593Smuzhiyun#endif
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun	string	cpu_v6_name, "ARMv6-compatible processor"
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun	.align
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun/*
181*4882a593Smuzhiyun *	__v6_setup
182*4882a593Smuzhiyun *
183*4882a593Smuzhiyun *	Initialise TLB, Caches, and MMU state ready to switch the MMU
184*4882a593Smuzhiyun *	on.  Return in r0 the new CP15 C1 control register setting.
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun *	We automatically detect if we have a Harvard cache, and use the
187*4882a593Smuzhiyun *	Harvard cache control instructions insead of the unified cache
188*4882a593Smuzhiyun *	control instructions.
189*4882a593Smuzhiyun *
190*4882a593Smuzhiyun *	This should be able to cover all ARMv6 cores.
191*4882a593Smuzhiyun *
192*4882a593Smuzhiyun *	It is assumed that:
193*4882a593Smuzhiyun *	- cache type register is implemented
194*4882a593Smuzhiyun */
195*4882a593Smuzhiyun__v6_setup:
196*4882a593Smuzhiyun#ifdef CONFIG_SMP
197*4882a593Smuzhiyun	ALT_SMP(mrc	p15, 0, r0, c1, c0, 1)	@ Enable SMP/nAMP mode
198*4882a593Smuzhiyun	ALT_UP(nop)
199*4882a593Smuzhiyun	orr	r0, r0, #0x20
200*4882a593Smuzhiyun	ALT_SMP(mcr	p15, 0, r0, c1, c0, 1)
201*4882a593Smuzhiyun	ALT_UP(nop)
202*4882a593Smuzhiyun#endif
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun	mov	r0, #0
205*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c14, 0		@ clean+invalidate D cache
206*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
207*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c15, 0		@ clean+invalidate cache
208*4882a593Smuzhiyun#ifdef CONFIG_MMU
209*4882a593Smuzhiyun	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
210*4882a593Smuzhiyun	mcr	p15, 0, r0, c2, c0, 2		@ TTB control register
211*4882a593Smuzhiyun	ALT_SMP(orr	r4, r4, #TTB_FLAGS_SMP)
212*4882a593Smuzhiyun	ALT_UP(orr	r4, r4, #TTB_FLAGS_UP)
213*4882a593Smuzhiyun	ALT_SMP(orr	r8, r8, #TTB_FLAGS_SMP)
214*4882a593Smuzhiyun	ALT_UP(orr	r8, r8, #TTB_FLAGS_UP)
215*4882a593Smuzhiyun	mcr	p15, 0, r8, c2, c0, 1		@ load TTB1
216*4882a593Smuzhiyun#endif /* CONFIG_MMU */
217*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer and
218*4882a593Smuzhiyun						@ complete invalidations
219*4882a593Smuzhiyun	adr	r5, v6_crval
220*4882a593Smuzhiyun	ldmia	r5, {r5, r6}
221*4882a593Smuzhiyun ARM_BE8(orr	r6, r6, #1 << 25)		@ big-endian page tables
222*4882a593Smuzhiyun	mrc	p15, 0, r0, c1, c0, 0		@ read control register
223*4882a593Smuzhiyun	bic	r0, r0, r5			@ clear bits them
224*4882a593Smuzhiyun	orr	r0, r0, r6			@ set them
225*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_364296
226*4882a593Smuzhiyun	/*
227*4882a593Smuzhiyun	 * Workaround for the 364296 ARM1136 r0p2 erratum (possible cache data
228*4882a593Smuzhiyun	 * corruption with hit-under-miss enabled). The conditional code below
229*4882a593Smuzhiyun	 * (setting the undocumented bit 31 in the auxiliary control register
230*4882a593Smuzhiyun	 * and the FI bit in the control register) disables hit-under-miss
231*4882a593Smuzhiyun	 * without putting the processor into full low interrupt latency mode.
232*4882a593Smuzhiyun	 */
233*4882a593Smuzhiyun	ldr	r6, =0x4107b362			@ id for ARM1136 r0p2
234*4882a593Smuzhiyun	mrc	p15, 0, r5, c0, c0, 0		@ get processor id
235*4882a593Smuzhiyun	teq	r5, r6				@ check for the faulty core
236*4882a593Smuzhiyun	mrceq	p15, 0, r5, c1, c0, 1		@ load aux control reg
237*4882a593Smuzhiyun	orreq	r5, r5, #(1 << 31)		@ set the undocumented bit 31
238*4882a593Smuzhiyun	mcreq	p15, 0, r5, c1, c0, 1		@ write aux control reg
239*4882a593Smuzhiyun	orreq	r0, r0, #(1 << 21)		@ low interrupt latency configuration
240*4882a593Smuzhiyun#endif
241*4882a593Smuzhiyun	ret	lr				@ return to head.S:__ret
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun	/*
244*4882a593Smuzhiyun	 *         V X F   I D LR
245*4882a593Smuzhiyun	 * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
246*4882a593Smuzhiyun	 * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
247*4882a593Smuzhiyun	 *         0 110       0011 1.00 .111 1101 < we want
248*4882a593Smuzhiyun	 */
249*4882a593Smuzhiyun	.type	v6_crval, #object
250*4882a593Smuzhiyunv6_crval:
251*4882a593Smuzhiyun	crval	clear=0x01e0fb7f, mmuset=0x00c0387d, ucset=0x00c0187c
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun	__INITDATA
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
256*4882a593Smuzhiyun	define_processor_functions v6, dabort=v6_early_abort, pabort=v6_pabort, suspend=1
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun	.section ".rodata"
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun	string	cpu_arch_name, "armv6"
261*4882a593Smuzhiyun	string	cpu_elf_name, "v6"
262*4882a593Smuzhiyun	.align
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun	.section ".proc.info.init", "a"
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun	/*
267*4882a593Smuzhiyun	 * Match any ARMv6 processor core.
268*4882a593Smuzhiyun	 */
269*4882a593Smuzhiyun	.type	__v6_proc_info, #object
270*4882a593Smuzhiyun__v6_proc_info:
271*4882a593Smuzhiyun	.long	0x0007b000
272*4882a593Smuzhiyun	.long	0x0007f000
273*4882a593Smuzhiyun	ALT_SMP(.long \
274*4882a593Smuzhiyun		PMD_TYPE_SECT | \
275*4882a593Smuzhiyun		PMD_SECT_AP_WRITE | \
276*4882a593Smuzhiyun		PMD_SECT_AP_READ | \
277*4882a593Smuzhiyun		PMD_FLAGS_SMP)
278*4882a593Smuzhiyun	ALT_UP(.long \
279*4882a593Smuzhiyun		PMD_TYPE_SECT | \
280*4882a593Smuzhiyun		PMD_SECT_AP_WRITE | \
281*4882a593Smuzhiyun		PMD_SECT_AP_READ | \
282*4882a593Smuzhiyun		PMD_FLAGS_UP)
283*4882a593Smuzhiyun	.long   PMD_TYPE_SECT | \
284*4882a593Smuzhiyun		PMD_SECT_XN | \
285*4882a593Smuzhiyun		PMD_SECT_AP_WRITE | \
286*4882a593Smuzhiyun		PMD_SECT_AP_READ
287*4882a593Smuzhiyun	initfn	__v6_setup, __v6_proc_info
288*4882a593Smuzhiyun	.long	cpu_arch_name
289*4882a593Smuzhiyun	.long	cpu_elf_name
290*4882a593Smuzhiyun	/* See also feat_v6_fixup() for HWCAP_TLS */
291*4882a593Smuzhiyun	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA|HWCAP_TLS
292*4882a593Smuzhiyun	.long	cpu_v6_name
293*4882a593Smuzhiyun	.long	v6_processor_functions
294*4882a593Smuzhiyun	.long	v6wbi_tlb_fns
295*4882a593Smuzhiyun	.long	v6_user_fns
296*4882a593Smuzhiyun	.long	v6_cache_fns
297*4882a593Smuzhiyun	.size	__v6_proc_info, . - __v6_proc_info
298