code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 *  linux/arch/arm/mm/proc-mohawk.S: MMU functions for Marvell PJ1 core
 *
 *  PJ1 (codename Mohawk) is a hybrid of the xscale3 and Marvell's own core.
 *
 *  Heavily based on proc-arm926.S and proc-xsc3.S
 */

#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/pgtable.h>
#include <asm/assembler.h>
#include <asm/hwcap.h>
#include <asm/pgtable-hwdef.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include "proc-macros.S"

/*
 * This is the maximum size of an area which will be flushed.  If the
 * area is larger than this, then we flush the whole cache.
 */
#define CACHE_DLIMIT	32768

/*
 * The cache line size of the L1 D cache.
 */
#define CACHE_DLINESIZE	32

/*
 * cpu_mohawk_proc_init()
 */
ENTRY(cpu_mohawk_proc_init)
	ret	lr

/*
 * cpu_mohawk_proc_fin()
 */
ENTRY(cpu_mohawk_proc_fin)
	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
	bic	r0, r0, #0x1800			@ ...iz...........
	bic	r0, r0, #0x0006			@ .............ca.
	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
	ret	lr

/*
 * cpu_mohawk_reset(loc)
 *
 * Perform a soft reset of the system.  Put the CPU into the
 * same state as it would be if it had been reset, and branch
 * to what would be the reset vector.
 *
 * loc: location to jump to for soft reset
 *
 * (same as arm926)
 */
	.align	5
	.pushsection	.idmap.text, "ax"
ENTRY(cpu_mohawk_reset)
	mov	ip, #0
	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
	bic	ip, ip, #0x0007			@ .............cam
	bic	ip, ip, #0x1100			@ ...i...s........
	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
	ret	r0
ENDPROC(cpu_mohawk_reset)
	.popsection

/*
 * cpu_mohawk_do_idle()
 *
 * Called with IRQs disabled
 */
	.align	5
ENTRY(cpu_mohawk_do_idle)
	mov	r0, #0
	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
	mcr	p15, 0, r0, c7, c0, 4		@ wait for interrupt
	ret	lr

/*
 *	flush_icache_all()
 *
 *	Unconditionally clean and invalidate the entire icache.
 */
ENTRY(mohawk_flush_icache_all)
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
	ret	lr
ENDPROC(mohawk_flush_icache_all)

/*
 *	flush_user_cache_all()
 *
 *	Clean and invalidate all cache entries in a particular
 *	address space.
 */
ENTRY(mohawk_flush_user_cache_all)
	/* FALLTHROUGH */

/*
 *	flush_kern_cache_all()
 *
 *	Clean and invalidate the entire cache.
 */
ENTRY(mohawk_flush_kern_cache_all)
	mov	r2, #VM_EXEC
	mov	ip, #0
__flush_whole_cache:
	mcr	p15, 0, ip, c7, c14, 0		@ clean & invalidate all D cache
	tst	r2, #VM_EXEC
	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
	mcrne	p15, 0, ip, c7, c10, 0		@ drain write buffer
	ret	lr

/*
 *	flush_user_cache_range(start, end, flags)
 *
 *	Clean and invalidate a range of cache entries in the
 *	specified address range.
 *
 *	- start	- start address (inclusive)
 *	- end	- end address (exclusive)
 *	- flags	- vm_flags describing address space
 *
 * (same as arm926)
 */
ENTRY(mohawk_flush_user_cache_range)
	mov	ip, #0
	sub	r3, r1, r0			@ calculate total size
	cmp	r3, #CACHE_DLIMIT
	bgt	__flush_whole_cache
1:	tst	r2, #VM_EXEC
	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
	add	r0, r0, #CACHE_DLINESIZE
	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	tst	r2, #VM_EXEC
	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
	ret	lr

/*
 *	coherent_kern_range(start, end)
 *
 *	Ensure coherency between the Icache and the Dcache in the
 *	region described by start, end.  If you have non-snooping
 *	Harvard caches, you need to implement this function.
 *
 *	- start	- virtual start address
 *	- end	- virtual end address
 */
ENTRY(mohawk_coherent_kern_range)
	/* FALLTHROUGH */

/*
 *	coherent_user_range(start, end)
 *
 *	Ensure coherency between the Icache and the Dcache in the
 *	region described by start, end.  If you have non-snooping
 *	Harvard caches, you need to implement this function.
 *
 *	- start	- virtual start address
 *	- end	- virtual end address
 *
 * (same as arm926)
 */
ENTRY(mohawk_coherent_user_range)
	bic	r0, r0, #CACHE_DLINESIZE - 1
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	mov	r0, #0
	ret	lr

/*
 *	flush_kern_dcache_area(void *addr, size_t size)
 *
 *	Ensure no D cache aliasing occurs, either with itself or
 *	the I cache
 *
 *	- addr	- kernel address
 *	- size	- region size
 */
ENTRY(mohawk_flush_kern_dcache_area)
	add	r1, r0, r1
1:	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	ret	lr

/*
 *	dma_inv_range(start, end)
 *
 *	Invalidate (discard) the specified virtual address range.
 *	May not write back any entries.  If 'start' or 'end'
 *	are not cache line aligned, those lines must be written
 *	back.
 *
 *	- start	- virtual start address
 *	- end	- virtual end address
 *
 * (same as v4wb)
 */
mohawk_dma_inv_range:
	tst	r0, #CACHE_DLINESIZE - 1
	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
	tst	r1, #CACHE_DLINESIZE - 1
	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
	bic	r0, r0, #CACHE_DLINESIZE - 1
1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	ret	lr

/*
 *	dma_clean_range(start, end)
 *
 *	Clean the specified virtual address range.
 *
 *	- start	- virtual start address
 *	- end	- virtual end address
 *
 * (same as v4wb)
 */
mohawk_dma_clean_range:
	bic	r0, r0, #CACHE_DLINESIZE - 1
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	ret	lr

/*
 *	dma_flush_range(start, end)
 *
 *	Clean and invalidate the specified virtual address range.
 *
 *	- start	- virtual start address
 *	- end	- virtual end address
 */
ENTRY(mohawk_dma_flush_range)
	bic	r0, r0, #CACHE_DLINESIZE - 1
1:
	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
	add	r0, r0, #CACHE_DLINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	ret	lr

/*
 *	dma_map_area(start, size, dir)
 *	- start	- kernel virtual start address
 *	- size	- size of region
 *	- dir	- DMA direction
 */
ENTRY(mohawk_dma_map_area)
	add	r1, r1, r0
	cmp	r2, #DMA_TO_DEVICE
	beq	mohawk_dma_clean_range
	bcs	mohawk_dma_inv_range
	b	mohawk_dma_flush_range
ENDPROC(mohawk_dma_map_area)

/*
 *	dma_unmap_area(start, size, dir)
 *	- start	- kernel virtual start address
 *	- size	- size of region
 *	- dir	- DMA direction
 */
ENTRY(mohawk_dma_unmap_area)
	ret	lr
ENDPROC(mohawk_dma_unmap_area)

	.globl	mohawk_flush_kern_cache_louis
	.equ	mohawk_flush_kern_cache_louis, mohawk_flush_kern_cache_all

	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
	define_cache_functions mohawk

ENTRY(cpu_mohawk_dcache_clean_area)
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	add	r0, r0, #CACHE_DLINESIZE
	subs	r1, r1, #CACHE_DLINESIZE
	bhi	1b
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	ret	lr

/*
 * cpu_mohawk_switch_mm(pgd)
 *
 * Set the translation base pointer to be as described by pgd.
 *
 * pgd: new page tables
 */
	.align	5
ENTRY(cpu_mohawk_switch_mm)
	mov	ip, #0
	mcr	p15, 0, ip, c7, c14, 0		@ clean & invalidate all D cache
	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
	orr	r0, r0, #0x18			@ cache the page table in L2
	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
	ret	lr

/*
 * cpu_mohawk_set_pte_ext(ptep, pte, ext)
 *
 * Set a PTE and flush it out
 */
	.align	5
ENTRY(cpu_mohawk_set_pte_ext)
#ifdef CONFIG_MMU
	armv3_set_pte_ext
	mov	r0, r0
	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
	ret	lr
#endif

.globl	cpu_mohawk_suspend_size
.equ	cpu_mohawk_suspend_size, 4 * 6
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_mohawk_do_suspend)
	stmfd	sp!, {r4 - r9, lr}
	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
	mrc	p15, 0, r6, c13, c0, 0	@ PID
	mrc 	p15, 0, r7, c3, c0, 0	@ domain ID
	mrc	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
	mrc 	p15, 0, r9, c1, c0, 0	@ control reg
	bic	r4, r4, #2		@ clear frequency change bit
	stmia	r0, {r4 - r9}		@ store cp regs
	ldmia	sp!, {r4 - r9, pc}
ENDPROC(cpu_mohawk_do_suspend)

ENTRY(cpu_mohawk_do_resume)
	ldmia	r0, {r4 - r9}		@ load cp regs
	mov	ip, #0
	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
	mcr	p15, 0, ip, c7, c10, 4	@ drain write (&fill) buffer
	mcr	p15, 0, ip, c7, c5, 4	@ flush prefetch buffer
	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
	mcr	p15, 0, r6, c13, c0, 0	@ PID
	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
	orr	r1, r1, #0x18		@ cache the page table in L2
	mcr	p15, 0, r1, c2, c0, 0	@ translation table base addr
	mcr	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
	mov	r0, r9			@ control register
	b	cpu_resume_mmu
ENDPROC(cpu_mohawk_do_resume)
#endif

	.type	__mohawk_setup, #function
__mohawk_setup:
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches
	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs
	orr	r4, r4, #0x18			@ cache the page table in L2
	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer

	mov	r0, #0				@ don't allow CP access
	mcr	p15, 0, r0, c15, c1, 0		@ write CP access register

	adr	r5, mohawk_crval
	ldmia	r5, {r5, r6}
	mrc	p15, 0, r0, c1, c0		@ get control register
	bic	r0, r0, r5
	orr	r0, r0, r6
	ret	lr

	.size	__mohawk_setup, . - __mohawk_setup

	/*
	 *  R
	 * .RVI ZFRS BLDP WCAM
	 * .011 1001 ..00 0101
	 *
	 */
	.type	mohawk_crval, #object
mohawk_crval:
	crval	clear=0x00007f3f, mmuset=0x00003905, ucset=0x00001134

	__INITDATA

	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
	define_processor_functions mohawk, dabort=v5t_early_abort, pabort=legacy_pabort

	.section ".rodata"

	string	cpu_arch_name, "armv5te"
	string	cpu_elf_name, "v5"
	string	cpu_mohawk_name, "Marvell 88SV331x"

	.align

	.section ".proc.info.init", "a"

	.type	__88sv331x_proc_info,#object
__88sv331x_proc_info:
	.long	0x56158000			@ Marvell 88SV331x (MOHAWK)
	.long	0xfffff000
	.long   PMD_TYPE_SECT | \
		PMD_SECT_BUFFERABLE | \
		PMD_SECT_CACHEABLE | \
		PMD_BIT4 | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	.long   PMD_TYPE_SECT | \
		PMD_BIT4 | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	initfn	__mohawk_setup, __88sv331x_proc_info
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
	.long	cpu_mohawk_name
	.long	mohawk_processor_functions
	.long	v4wbi_tlb_fns
	.long	v4wb_user_fns
	.long	mohawk_cache_fns
	.size	__88sv331x_proc_info, . - __88sv331x_proc_info


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mm/proc-sa110.S
 *
 *  Copyright (C) 1997-2002 Russell King
 *  hacked for non-paged-MM by Hyok S. Choi, 2003.
 *
 *  MMU functions for SA110
 *
 *  These are the low level assembler for performing cache and TLB
 *  functions on the StrongARM-110.
 */
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/pgtable.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hwcap.h>
#include <mach/hardware.h>
#include <asm/pgtable-hwdef.h>
#include <asm/ptrace.h>

#include "proc-macros.S"

/*
 * the cache line size of the I and D cache
 */
#define DCACHELINESIZE	32

	.text

/*
 * cpu_sa110_proc_init()
 */
ENTRY(cpu_sa110_proc_init)
	mov	r0, #0
	mcr	p15, 0, r0, c15, c1, 2		@ Enable clock switching
	ret	lr

/*
 * cpu_sa110_proc_fin()
 */
ENTRY(cpu_sa110_proc_fin)
	mov	r0, #0
	mcr	p15, 0, r0, c15, c2, 2		@ Disable clock switching
	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
	bic	r0, r0, #0x1000			@ ...i............
	bic	r0, r0, #0x000e			@ ............wca.
	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
	ret	lr

/*
 * cpu_sa110_reset(loc)
 *
 * Perform a soft reset of the system.  Put the CPU into the
 * same state as it would be if it had been reset, and branch
 * to what would be the reset vector.
 *
 * loc: location to jump to for soft reset
 */
	.align	5
	.pushsection	.idmap.text, "ax"
ENTRY(cpu_sa110_reset)
	mov	ip, #0
	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
#ifdef CONFIG_MMU
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
#endif
	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
	bic	ip, ip, #0x000f			@ ............wcam
	bic	ip, ip, #0x1100			@ ...i...s........
	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
	ret	r0
ENDPROC(cpu_sa110_reset)
	.popsection

/*
 * cpu_sa110_do_idle(type)
 *
 * Cause the processor to idle
 *
 * type: call type:
 *   0 = slow idle
 *   1 = fast idle
 *   2 = switch to slow processor clock
 *   3 = switch to fast processor clock
 */
	.align	5

ENTRY(cpu_sa110_do_idle)
	mcr	p15, 0, ip, c15, c2, 2		@ disable clock switching
	ldr	r1, =UNCACHEABLE_ADDR		@ load from uncacheable loc
	ldr	r1, [r1, #0]			@ force switch to MCLK
	mov	r0, r0				@ safety
	mov	r0, r0				@ safety
	mov	r0, r0				@ safety
	mcr	p15, 0, r0, c15, c8, 2		@ Wait for interrupt, cache aligned
	mov	r0, r0				@ safety
	mov	r0, r0				@ safety
	mov	r0, r0				@ safety
	mcr	p15, 0, r0, c15, c1, 2		@ enable clock switching
	ret	lr

/* ================================= CACHE ================================ */

/*
 * cpu_sa110_dcache_clean_area(addr,sz)
 *
 * Clean the specified entry of any caches such that the MMU
 * translation fetches will obtain correct data.
 *
 * addr: cache-unaligned virtual address
 */
	.align	5
ENTRY(cpu_sa110_dcache_clean_area)
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	add	r0, r0, #DCACHELINESIZE
	subs	r1, r1, #DCACHELINESIZE
	bhi	1b
	ret	lr

/* =============================== PageTable ============================== */

/*
 * cpu_sa110_switch_mm(pgd)
 *
 * Set the translation base pointer to be as described by pgd.
 *
 * pgd: new page tables
 */
	.align	5
ENTRY(cpu_sa110_switch_mm)
#ifdef CONFIG_MMU
	str	lr, [sp, #-4]!
	bl	v4wb_flush_kern_cache_all	@ clears IP
	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
	ldr	pc, [sp], #4
#else
	ret	lr
#endif

/*
 * cpu_sa110_set_pte_ext(ptep, pte, ext)
 *
 * Set a PTE and flush it out
 */
	.align	5
ENTRY(cpu_sa110_set_pte_ext)
#ifdef CONFIG_MMU
	armv3_set_pte_ext wc_disable=0
	mov	r0, r0
	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
#endif
	ret	lr

	.type	__sa110_setup, #function
__sa110_setup:
	mov	r10, #0
	mcr	p15, 0, r10, c7, c7		@ invalidate I,D caches on v4
	mcr	p15, 0, r10, c7, c10, 4		@ drain write buffer on v4
#ifdef CONFIG_MMU
	mcr	p15, 0, r10, c8, c7		@ invalidate I,D TLBs on v4
#endif

	adr	r5, sa110_crval
	ldmia	r5, {r5, r6}
	mrc	p15, 0, r0, c1, c0		@ get control register v4
	bic	r0, r0, r5
	orr	r0, r0, r6
	ret	lr
	.size	__sa110_setup, . - __sa110_setup

	/*
	 *  R
	 * .RVI ZFRS BLDP WCAM
	 * ..01 0001 ..11 1101
	 *
	 */
	.type	sa110_crval, #object
sa110_crval:
	crval	clear=0x00003f3f, mmuset=0x0000113d, ucset=0x00001130

	__INITDATA

	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
	define_processor_functions sa110, dabort=v4_early_abort, pabort=legacy_pabort

	.section ".rodata"

	string	cpu_arch_name, "armv4"
	string	cpu_elf_name, "v4"
	string	cpu_sa110_name, "StrongARM-110"

	.align

	.section ".proc.info.init", "a"

	.type	__sa110_proc_info,#object
__sa110_proc_info:
	.long	0x4401a100
	.long	0xfffffff0
	.long   PMD_TYPE_SECT | \
		PMD_SECT_BUFFERABLE | \
		PMD_SECT_CACHEABLE | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	.long   PMD_TYPE_SECT | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	initfn	__sa110_setup, __sa110_proc_info
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
	.long	cpu_sa110_name
	.long	sa110_processor_functions
	.long	v4wb_tlb_fns
	.long	v4wb_user_fns
	.long	v4wb_cache_fns
	.size	__sa110_proc_info, . - __sa110_proc_info

repo_name: angery/linux


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mm/proc-sa1100.S
 *
 *  Copyright (C) 1997-2002 Russell King
 *  hacked for non-paged-MM by Hyok S. Choi, 2003.
 *
 *  MMU functions for SA110
 *
 *  These are the low level assembler for performing cache and TLB
 *  functions on the StrongARM-1100 and StrongARM-1110.
 *
 *  Note that SA1100 and SA1110 share everything but their name and CPU ID.
 *
 *  12-jun-2000, Erik Mouw (J.A.K.Mouw@its.tudelft.nl):
 *    Flush the read buffer at context switches
 */
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/pgtable.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hwcap.h>
#include <mach/hardware.h>
#include <asm/pgtable-hwdef.h>

#include "proc-macros.S"

/*
 * the cache line size of the I and D cache
 */
#define DCACHELINESIZE	32

	.section .text

/*
 * cpu_sa1100_proc_init()
 */
ENTRY(cpu_sa1100_proc_init)
	mov	r0, #0
	mcr	p15, 0, r0, c15, c1, 2		@ Enable clock switching
	mcr	p15, 0, r0, c9, c0, 5		@ Allow read-buffer operations from userland
	ret	lr

/*
 * cpu_sa1100_proc_fin()
 *
 * Prepare the CPU for reset:
 *  - Disable interrupts
 *  - Clean and turn off caches.
 */
ENTRY(cpu_sa1100_proc_fin)
	mcr	p15, 0, ip, c15, c2, 2		@ Disable clock switching
	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
	bic	r0, r0, #0x1000			@ ...i............
	bic	r0, r0, #0x000e			@ ............wca.
	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
	ret	lr

/*
 * cpu_sa1100_reset(loc)
 *
 * Perform a soft reset of the system.  Put the CPU into the
 * same state as it would be if it had been reset, and branch
 * to what would be the reset vector.
 *
 * loc: location to jump to for soft reset
 */
	.align	5
	.pushsection	.idmap.text, "ax"
ENTRY(cpu_sa1100_reset)
	mov	ip, #0
	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
#ifdef CONFIG_MMU
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
#endif
	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
	bic	ip, ip, #0x000f			@ ............wcam
	bic	ip, ip, #0x1100			@ ...i...s........
	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
	ret	r0
ENDPROC(cpu_sa1100_reset)
	.popsection

/*
 * cpu_sa1100_do_idle(type)
 *
 * Cause the processor to idle
 *
 * type: call type:
 *   0 = slow idle
 *   1 = fast idle
 *   2 = switch to slow processor clock
 *   3 = switch to fast processor clock
 */
	.align	5
ENTRY(cpu_sa1100_do_idle)
	mov	r0, r0				@ 4 nop padding
	mov	r0, r0
	mov	r0, r0
	mov	r0, r0				@ 4 nop padding
	mov	r0, r0
	mov	r0, r0
	mov	r0, #0
	ldr	r1, =UNCACHEABLE_ADDR		@ ptr to uncacheable address
	@ --- aligned to a cache line
	mcr	p15, 0, r0, c15, c2, 2		@ disable clock switching
	ldr	r1, [r1, #0]			@ force switch to MCLK
	mcr	p15, 0, r0, c15, c8, 2		@ wait for interrupt
	mov	r0, r0				@ safety
	mcr	p15, 0, r0, c15, c1, 2		@ enable clock switching
	ret	lr

/* ================================= CACHE ================================ */

/*
 * cpu_sa1100_dcache_clean_area(addr,sz)
 *
 * Clean the specified entry of any caches such that the MMU
 * translation fetches will obtain correct data.
 *
 * addr: cache-unaligned virtual address
 */
	.align	5
ENTRY(cpu_sa1100_dcache_clean_area)
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	add	r0, r0, #DCACHELINESIZE
	subs	r1, r1, #DCACHELINESIZE
	bhi	1b
	ret	lr

/* =============================== PageTable ============================== */

/*
 * cpu_sa1100_switch_mm(pgd)
 *
 * Set the translation base pointer to be as described by pgd.
 *
 * pgd: new page tables
 */
	.align	5
ENTRY(cpu_sa1100_switch_mm)
#ifdef CONFIG_MMU
	str	lr, [sp, #-4]!
	bl	v4wb_flush_kern_cache_all	@ clears IP
	mcr	p15, 0, ip, c9, c0, 0		@ invalidate RB
	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
	ldr	pc, [sp], #4
#else
	ret	lr
#endif

/*
 * cpu_sa1100_set_pte_ext(ptep, pte, ext)
 *
 * Set a PTE and flush it out
 */
	.align	5
ENTRY(cpu_sa1100_set_pte_ext)
#ifdef CONFIG_MMU
	armv3_set_pte_ext wc_disable=0
	mov	r0, r0
	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
#endif
	ret	lr

.globl	cpu_sa1100_suspend_size
.equ	cpu_sa1100_suspend_size, 4 * 3
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_sa1100_do_suspend)
	stmfd	sp!, {r4 - r6, lr}
	mrc	p15, 0, r4, c3, c0, 0		@ domain ID
	mrc	p15, 0, r5, c13, c0, 0		@ PID
	mrc	p15, 0, r6, c1, c0, 0		@ control reg
	stmia	r0, {r4 - r6}			@ store cp regs
	ldmfd	sp!, {r4 - r6, pc}
ENDPROC(cpu_sa1100_do_suspend)

ENTRY(cpu_sa1100_do_resume)
	ldmia	r0, {r4 - r6}			@ load cp regs
	mov	ip, #0
	mcr	p15, 0, ip, c8, c7, 0		@ flush I+D TLBs
	mcr	p15, 0, ip, c7, c7, 0		@ flush I&D cache
	mcr	p15, 0, ip, c9, c0, 0		@ invalidate RB
	mcr	p15, 0, ip, c9, c0, 5		@ allow user space to use RB

	mcr	p15, 0, r4, c3, c0, 0		@ domain ID
	mcr	p15, 0, r1, c2, c0, 0		@ translation table base addr
	mcr	p15, 0, r5, c13, c0, 0		@ PID
	mov	r0, r6				@ control register
	b	cpu_resume_mmu
ENDPROC(cpu_sa1100_do_resume)
#endif

	.type	__sa1100_setup, #function
__sa1100_setup:
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
#ifdef CONFIG_MMU
	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
#endif
	adr	r5, sa1100_crval
	ldmia	r5, {r5, r6}
	mrc	p15, 0, r0, c1, c0		@ get control register v4
	bic	r0, r0, r5
	orr	r0, r0, r6
	ret	lr
	.size	__sa1100_setup, . - __sa1100_setup

	/*
	 *  R
	 * .RVI ZFRS BLDP WCAM
	 * ..11 0001 ..11 1101
	 *
	 */
	.type	sa1100_crval, #object
sa1100_crval:
	crval	clear=0x00003f3f, mmuset=0x0000313d, ucset=0x00001130

	__INITDATA

/*
 * SA1100 and SA1110 share the same function calls
 */

	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
	define_processor_functions sa1100, dabort=v4_early_abort, pabort=legacy_pabort, suspend=1

	.section ".rodata"

	string	cpu_arch_name, "armv4"
	string	cpu_elf_name, "v4"
	string	cpu_sa1100_name, "StrongARM-1100"
	string	cpu_sa1110_name, "StrongARM-1110"

	.align

	.section ".proc.info.init", "a"

.macro sa1100_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
	.type	__\name\()_proc_info,#object
__\name\()_proc_info:
	.long	\cpu_val
	.long	\cpu_mask
	.long   PMD_TYPE_SECT | \
		PMD_SECT_BUFFERABLE | \
		PMD_SECT_CACHEABLE | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	.long   PMD_TYPE_SECT | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	initfn	__sa1100_setup, __\name\()_proc_info
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
	.long	\cpu_name
	.long	sa1100_processor_functions
	.long	v4wb_tlb_fns
	.long	v4_mc_user_fns
	.long	v4wb_cache_fns
	.size	__\name\()_proc_info, . - __\name\()_proc_info
.endm

	sa1100_proc_info sa1100, 0x4401a110, 0xfffffff0, cpu_sa1100_name
	sa1100_proc_info sa1110, 0x6901b110, 0xfffffff0, cpu_sa1110_name


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  linux/arch/arm/mm/proc-syms.c
 *
 *  Copyright (C) 2000-2002 Russell King
 */
#include <linux/module.h>
#include <linux/mm.h>

#include <asm/cacheflush.h>
#include <asm/proc-fns.h>
#include <asm/tlbflush.h>
#include <asm/page.h>

#ifndef MULTI_CPU
EXPORT_SYMBOL(cpu_dcache_clean_area);
#ifdef CONFIG_MMU
EXPORT_SYMBOL(cpu_set_pte_ext);
#endif
#else
EXPORT_SYMBOL(processor);
#endif

#ifndef MULTI_CACHE
EXPORT_SYMBOL(__cpuc_flush_kern_all);
EXPORT_SYMBOL(__cpuc_flush_user_all);
EXPORT_SYMBOL(__cpuc_flush_user_range);
EXPORT_SYMBOL(__cpuc_coherent_kern_range);
EXPORT_SYMBOL(__cpuc_flush_dcache_area);
#else
EXPORT_SYMBOL(cpu_cache);
#endif

#ifdef CONFIG_MMU
#ifndef MULTI_USER
EXPORT_SYMBOL(__cpu_clear_user_highpage);
EXPORT_SYMBOL(__cpu_copy_user_highpage);
#else
EXPORT_SYMBOL(cpu_user);
#endif
#endif

/*
 * No module should need to touch the TLB (and currently
 * no modules do.  We export this for "loadkernel" support
 * (booting a new kernel from within a running kernel.)
 */
#ifdef MULTI_TLB
EXPORT_SYMBOL(cpu_tlb);
#endif


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mm/proc-v6.S
 *
 *  Copyright (C) 2001 Deep Blue Solutions Ltd.
 *  Modified by Catalin Marinas for noMMU support
 *
 *  This is the "shell" of the ARMv6 processor support.
 */
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/pgtable.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hwcap.h>
#include <asm/pgtable-hwdef.h>

#include "proc-macros.S"

#define D_CACHE_LINE_SIZE	32

#define TTB_C		(1 << 0)
#define TTB_S		(1 << 1)
#define TTB_IMP		(1 << 2)
#define TTB_RGN_NC	(0 << 3)
#define TTB_RGN_WBWA	(1 << 3)
#define TTB_RGN_WT	(2 << 3)
#define TTB_RGN_WB	(3 << 3)

#define TTB_FLAGS_UP	TTB_RGN_WBWA
#define PMD_FLAGS_UP	PMD_SECT_WB
#define TTB_FLAGS_SMP	TTB_RGN_WBWA|TTB_S
#define PMD_FLAGS_SMP	PMD_SECT_WBWA|PMD_SECT_S

.arch armv6

ENTRY(cpu_v6_proc_init)
	ret	lr

ENTRY(cpu_v6_proc_fin)
	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
	bic	r0, r0, #0x1000			@ ...i............
	bic	r0, r0, #0x0006			@ .............ca.
	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
	ret	lr

/*
 *	cpu_v6_reset(loc)
 *
 *	Perform a soft reset of the system.  Put the CPU into the
 *	same state as it would be if it had been reset, and branch
 *	to what would be the reset vector.
 *
 *	- loc   - location to jump to for soft reset
 */
	.align	5
	.pushsection	.idmap.text, "ax"
ENTRY(cpu_v6_reset)
	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
	bic	r1, r1, #0x1			@ ...............m
	mcr	p15, 0, r1, c1, c0, 0		@ disable MMU
	mov	r1, #0
	mcr	p15, 0, r1, c7, c5, 4		@ ISB
	ret	r0
ENDPROC(cpu_v6_reset)
	.popsection

/*
 *	cpu_v6_do_idle()
 *
 *	Idle the processor (eg, wait for interrupt).
 *
 *	IRQs are already disabled.
 */
ENTRY(cpu_v6_do_idle)
	mov	r1, #0
	mcr	p15, 0, r1, c7, c10, 4		@ DWB - WFI may enter a low-power mode
	mcr	p15, 0, r1, c7, c0, 4		@ wait for interrupt
	ret	lr

ENTRY(cpu_v6_dcache_clean_area)
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	add	r0, r0, #D_CACHE_LINE_SIZE
	subs	r1, r1, #D_CACHE_LINE_SIZE
	bhi	1b
	ret	lr

/*
 *	cpu_v6_switch_mm(pgd_phys, tsk)
 *
 *	Set the translation table base pointer to be pgd_phys
 *
 *	- pgd_phys - physical address of new TTB
 *
 *	It is assumed that:
 *	- we are not using split page tables
 */
ENTRY(cpu_v6_switch_mm)
#ifdef CONFIG_MMU
	mov	r2, #0
	mmid	r1, r1				@ get mm->context.id
	ALT_SMP(orr	r0, r0, #TTB_FLAGS_SMP)
	ALT_UP(orr	r0, r0, #TTB_FLAGS_UP)
	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
	mcr	p15, 0, r2, c7, c10, 4		@ drain write buffer
	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
#ifdef CONFIG_PID_IN_CONTEXTIDR
	mrc	p15, 0, r2, c13, c0, 1		@ read current context ID
	bic	r2, r2, #0xff			@ extract the PID
	and	r1, r1, #0xff
	orr	r1, r1, r2			@ insert into new context ID
#endif
	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
#endif
	ret	lr

/*
 *	cpu_v6_set_pte_ext(ptep, pte, ext)
 *
 *	Set a level 2 translation table entry.
 *
 *	- ptep  - pointer to level 2 translation table entry
 *		  (hardware version is stored at -1024 bytes)
 *	- pte   - PTE value to store
 *	- ext	- value for extended PTE bits
 */
	armv6_mt_table cpu_v6

ENTRY(cpu_v6_set_pte_ext)
#ifdef CONFIG_MMU
	armv6_set_pte_ext cpu_v6
#endif
	ret	lr

/* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
.globl	cpu_v6_suspend_size
.equ	cpu_v6_suspend_size, 4 * 6
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_v6_do_suspend)
	stmfd	sp!, {r4 - r9, lr}
	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
#ifdef CONFIG_MMU
	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
	mrc	p15, 0, r6, c2, c0, 1	@ Translation table base 1
#endif
	mrc	p15, 0, r7, c1, c0, 1	@ auxiliary control register
	mrc	p15, 0, r8, c1, c0, 2	@ co-processor access control
	mrc	p15, 0, r9, c1, c0, 0	@ control register
	stmia	r0, {r4 - r9}
	ldmfd	sp!, {r4- r9, pc}
ENDPROC(cpu_v6_do_suspend)

ENTRY(cpu_v6_do_resume)
	mov	ip, #0
	mcr	p15, 0, ip, c7, c14, 0	@ clean+invalidate D cache
	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
	mcr	p15, 0, ip, c7, c15, 0	@ clean+invalidate cache
	mcr	p15, 0, ip, c7, c10, 4	@ drain write buffer
	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
	ldmia	r0, {r4 - r9}
	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
#ifdef CONFIG_MMU
	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
	ALT_UP(orr	r1, r1, #TTB_FLAGS_UP)
	mcr	p15, 0, r1, c2, c0, 0	@ Translation table base 0
	mcr	p15, 0, r6, c2, c0, 1	@ Translation table base 1
	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
#endif
	mcr	p15, 0, r7, c1, c0, 1	@ auxiliary control register
	mcr	p15, 0, r8, c1, c0, 2	@ co-processor access control
	mcr	p15, 0, ip, c7, c5, 4	@ ISB
	mov	r0, r9			@ control register
	b	cpu_resume_mmu
ENDPROC(cpu_v6_do_resume)
#endif

	string	cpu_v6_name, "ARMv6-compatible processor"

	.align

/*
 *	__v6_setup
 *
 *	Initialise TLB, Caches, and MMU state ready to switch the MMU
 *	on.  Return in r0 the new CP15 C1 control register setting.
 *
 *	We automatically detect if we have a Harvard cache, and use the
 *	Harvard cache control instructions insead of the unified cache
 *	control instructions.
 *
 *	This should be able to cover all ARMv6 cores.
 *
 *	It is assumed that:
 *	- cache type register is implemented
 */
__v6_setup:
#ifdef CONFIG_SMP
	ALT_SMP(mrc	p15, 0, r0, c1, c0, 1)	@ Enable SMP/nAMP mode
	ALT_UP(nop)
	orr	r0, r0, #0x20
	ALT_SMP(mcr	p15, 0, r0, c1, c0, 1)
	ALT_UP(nop)
#endif

	mov	r0, #0
	mcr	p15, 0, r0, c7, c14, 0		@ clean+invalidate D cache
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
	mcr	p15, 0, r0, c7, c15, 0		@ clean+invalidate cache
#ifdef CONFIG_MMU
	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
	mcr	p15, 0, r0, c2, c0, 2		@ TTB control register
	ALT_SMP(orr	r4, r4, #TTB_FLAGS_SMP)
	ALT_UP(orr	r4, r4, #TTB_FLAGS_UP)
	ALT_SMP(orr	r8, r8, #TTB_FLAGS_SMP)
	ALT_UP(orr	r8, r8, #TTB_FLAGS_UP)
	mcr	p15, 0, r8, c2, c0, 1		@ load TTB1
#endif /* CONFIG_MMU */
	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer and
						@ complete invalidations
	adr	r5, v6_crval
	ldmia	r5, {r5, r6}
 ARM_BE8(orr	r6, r6, #1 << 25)		@ big-endian page tables
	mrc	p15, 0, r0, c1, c0, 0		@ read control register
	bic	r0, r0, r5			@ clear bits them
	orr	r0, r0, r6			@ set them
#ifdef CONFIG_ARM_ERRATA_364296
	/*
	 * Workaround for the 364296 ARM1136 r0p2 erratum (possible cache data
	 * corruption with hit-under-miss enabled). The conditional code below
	 * (setting the undocumented bit 31 in the auxiliary control register
	 * and the FI bit in the control register) disables hit-under-miss
	 * without putting the processor into full low interrupt latency mode.
	 */
	ldr	r6, =0x4107b362			@ id for ARM1136 r0p2
	mrc	p15, 0, r5, c0, c0, 0		@ get processor id
	teq	r5, r6				@ check for the faulty core
	mrceq	p15, 0, r5, c1, c0, 1		@ load aux control reg
	orreq	r5, r5, #(1 << 31)		@ set the undocumented bit 31
	mcreq	p15, 0, r5, c1, c0, 1		@ write aux control reg
	orreq	r0, r0, #(1 << 21)		@ low interrupt latency configuration
#endif
	ret	lr				@ return to head.S:__ret

	/*
	 *         V X F   I D LR
	 * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
	 * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
	 *         0 110       0011 1.00 .111 1101 < we want
	 */
	.type	v6_crval, #object
v6_crval:
	crval	clear=0x01e0fb7f, mmuset=0x00c0387d, ucset=0x00c0187c

	__INITDATA

	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
	define_processor_functions v6, dabort=v6_early_abort, pabort=v6_pabort, suspend=1

	.section ".rodata"

	string	cpu_arch_name, "armv6"
	string	cpu_elf_name, "v6"
	.align

	.section ".proc.info.init", "a"

	/*
	 * Match any ARMv6 processor core.
	 */
	.type	__v6_proc_info, #object
__v6_proc_info:
	.long	0x0007b000
	.long	0x0007f000
	ALT_SMP(.long \
		PMD_TYPE_SECT | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ | \
		PMD_FLAGS_SMP)
	ALT_UP(.long \
		PMD_TYPE_SECT | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ | \
		PMD_FLAGS_UP)
	.long   PMD_TYPE_SECT | \
		PMD_SECT_XN | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	initfn	__v6_setup, __v6_proc_info
	.long	cpu_arch_name
	.long	cpu_elf_name
	/* See also feat_v6_fixup() for HWCAP_TLS */
	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA|HWCAP_TLS
	.long	cpu_v6_name
	.long	v6_processor_functions
	.long	v6wbi_tlb_fns
	.long	v6_user_fns
	.long	v6_cache_fns
	.size	__v6_proc_info, . - __v6_proc_info


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * arch/arm/mm/proc-v7-2level.S
 *
 * Copyright (C) 2001 Deep Blue Solutions Ltd.
 */

#define TTB_S		(1 << 1)
#define TTB_RGN_NC	(0 << 3)
#define TTB_RGN_OC_WBWA	(1 << 3)
#define TTB_RGN_OC_WT	(2 << 3)
#define TTB_RGN_OC_WB	(3 << 3)
#define TTB_NOS		(1 << 5)
#define TTB_IRGN_NC	((0 << 0) | (0 << 6))
#define TTB_IRGN_WBWA	((0 << 0) | (1 << 6))
#define TTB_IRGN_WT	((1 << 0) | (0 << 6))
#define TTB_IRGN_WB	((1 << 0) | (1 << 6))

/* PTWs cacheable, inner WB not shareable, outer WB not shareable */
#define TTB_FLAGS_UP	TTB_IRGN_WB|TTB_RGN_OC_WB
#define PMD_FLAGS_UP	PMD_SECT_WB

/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
#define TTB_FLAGS_SMP	TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
#define PMD_FLAGS_SMP	PMD_SECT_WBWA|PMD_SECT_S

.arch armv7-a

/*
 *	cpu_v7_switch_mm(pgd_phys, tsk)
 *
 *	Set the translation table base pointer to be pgd_phys
 *
 *	- pgd_phys - physical address of new TTB
 *
 *	It is assumed that:
 *	- we are not using split page tables
 *
 *	Note that we always need to flush BTAC/BTB if IBE is set
 *	even on Cortex-A8 revisions not affected by 430973.
 *	If IBE is not set, the flush BTAC/BTB won't do anything.
 */
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
	mmid	r1, r1				@ get mm->context.id
	ALT_SMP(orr	r0, r0, #TTB_FLAGS_SMP)
	ALT_UP(orr	r0, r0, #TTB_FLAGS_UP)
#ifdef CONFIG_PID_IN_CONTEXTIDR
	mrc	p15, 0, r2, c13, c0, 1		@ read current context ID
	lsr	r2, r2, #8			@ extract the PID
	bfi	r1, r2, #8, #24			@ insert into new context ID
#endif
#ifdef CONFIG_ARM_ERRATA_754322
	dsb
#endif
	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
	isb
	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
	isb
#endif
	bx	lr
ENDPROC(cpu_v7_switch_mm)

/*
 *	cpu_v7_set_pte_ext(ptep, pte)
 *
 *	Set a level 2 translation table entry.
 *
 *	- ptep  - pointer to level 2 translation table entry
 *		  (hardware version is stored at +2048 bytes)
 *	- pte   - PTE value to store
 *	- ext	- value for extended PTE bits
 */
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
	str	r1, [r0]			@ linux version

	bic	r3, r1, #0x000003f0
	bic	r3, r3, #PTE_TYPE_MASK
	orr	r3, r3, r2
	orr	r3, r3, #PTE_EXT_AP0 | 2

	tst	r1, #1 << 4
	orrne	r3, r3, #PTE_EXT_TEX(1)

	eor	r1, r1, #L_PTE_DIRTY
	tst	r1, #L_PTE_RDONLY | L_PTE_DIRTY
	orrne	r3, r3, #PTE_EXT_APX

	tst	r1, #L_PTE_USER
	orrne	r3, r3, #PTE_EXT_AP1

	tst	r1, #L_PTE_XN
	orrne	r3, r3, #PTE_EXT_XN

	tst	r1, #L_PTE_YOUNG
	tstne	r1, #L_PTE_VALID
	eorne	r1, r1, #L_PTE_NONE
	tstne	r1, #L_PTE_NONE
	moveq	r3, #0

 ARM(	str	r3, [r0, #2048]! )
 THUMB(	add	r0, r0, #2048 )
 THUMB(	str	r3, [r0] )
	ALT_SMP(W(nop))
	ALT_UP (mcr	p15, 0, r0, c7, c10, 1)		@ flush_pte
#endif
	bx	lr
ENDPROC(cpu_v7_set_pte_ext)

	/*
	 * Memory region attributes with SCTLR.TRE=1
	 *
	 *   n = TEX[0],C,B
	 *   TR = PRRR[2n+1:2n]		- memory type
	 *   IR = NMRR[2n+1:2n]		- inner cacheable property
	 *   OR = NMRR[2n+17:2n+16]	- outer cacheable property
	 *
	 *			n	TR	IR	OR
	 *   UNCACHED		000	00
	 *   BUFFERABLE		001	10	00	00
	 *   WRITETHROUGH	010	10	10	10
	 *   WRITEBACK		011	10	11	11
	 *   reserved		110
	 *   WRITEALLOC		111	10	01	01
	 *   DEV_SHARED		100	01
	 *   DEV_NONSHARED	100	01
	 *   DEV_WC		001	10
	 *   DEV_CACHED		011	10
	 *
	 * Other attributes:
	 *
	 *   DS0 = PRRR[16] = 0		- device shareable property
	 *   DS1 = PRRR[17] = 1		- device shareable property
	 *   NS0 = PRRR[18] = 0		- normal shareable property
	 *   NS1 = PRRR[19] = 1		- normal shareable property
	 *   NOS = PRRR[24+n] = 1	- not outer shareable
	 */
.equ	PRRR,	0xff0a81a8
.equ	NMRR,	0x40e040e0

	/*
	 * Macro for setting up the TTBRx and TTBCR registers.
	 * - \ttb0 and \ttb1 updated with the corresponding flags.
	 */
	.macro	v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp
	mcr	p15, 0, \zero, c2, c0, 2	@ TTB control register
	ALT_SMP(orr	\ttbr0l, \ttbr0l, #TTB_FLAGS_SMP)
	ALT_UP(orr	\ttbr0l, \ttbr0l, #TTB_FLAGS_UP)
	ALT_SMP(orr	\ttbr1, \ttbr1, #TTB_FLAGS_SMP)
	ALT_UP(orr	\ttbr1, \ttbr1, #TTB_FLAGS_UP)
	mcr	p15, 0, \ttbr1, c2, c0, 1	@ load TTB1
	.endm

	/*   AT
	 *  TFR   EV X F   I D LR    S
	 * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
	 * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
	 *   01    0 110       0011 1100 .111 1101 < we want
	 */
	.align	2
	.type	v7_crval, #object
v7_crval:
	crval	clear=0x2120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * arch/arm/mm/proc-v7-3level.S
 *
 * Copyright (C) 2001 Deep Blue Solutions Ltd.
 * Copyright (C) 2011 ARM Ltd.
 * Author: Catalin Marinas <catalin.marinas@arm.com>
 *   based on arch/arm/mm/proc-v7-2level.S
 */
#include <asm/assembler.h>

#define TTB_IRGN_NC	(0 << 8)
#define TTB_IRGN_WBWA	(1 << 8)
#define TTB_IRGN_WT	(2 << 8)
#define TTB_IRGN_WB	(3 << 8)
#define TTB_RGN_NC	(0 << 10)
#define TTB_RGN_OC_WBWA	(1 << 10)
#define TTB_RGN_OC_WT	(2 << 10)
#define TTB_RGN_OC_WB	(3 << 10)
#define TTB_S		(3 << 12)
#define TTB_EAE		(1 << 31)

/* PTWs cacheable, inner WB not shareable, outer WB not shareable */
#define TTB_FLAGS_UP	(TTB_IRGN_WB|TTB_RGN_OC_WB)
#define PMD_FLAGS_UP	(PMD_SECT_WB)

/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
#define TTB_FLAGS_SMP	(TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA)
#define PMD_FLAGS_SMP	(PMD_SECT_WBWA|PMD_SECT_S)

#ifndef __ARMEB__
#  define rpgdl	r0
#  define rpgdh	r1
#else
#  define rpgdl	r1
#  define rpgdh	r0
#endif

/*
 * cpu_v7_switch_mm(pgd_phys, tsk)
 *
 * Set the translation table base pointer to be pgd_phys (physical address of
 * the new TTB).
 */
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
	mmid	r2, r2
	asid	r2, r2
	orr	rpgdh, rpgdh, r2, lsl #(48 - 32)	@ upper 32-bits of pgd
	mcrr	p15, 0, rpgdl, rpgdh, c2		@ set TTB 0
	isb
#endif
	ret	lr
ENDPROC(cpu_v7_switch_mm)

#ifdef __ARMEB__
#define rl r3
#define rh r2
#else
#define rl r2
#define rh r3
#endif

/*
 * cpu_v7_set_pte_ext(ptep, pte)
 *
 * Set a level 2 translation table entry.
 * - ptep - pointer to level 3 translation table entry
 * - pte - PTE value to store (64-bit in r2 and r3)
 */
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
	tst	rl, #L_PTE_VALID
	beq	1f
	tst	rh, #1 << (57 - 32)		@ L_PTE_NONE
	bicne	rl, #L_PTE_VALID
	bne	1f

	eor	ip, rh, #1 << (55 - 32)	@ toggle L_PTE_DIRTY in temp reg to
					@ test for !L_PTE_DIRTY || L_PTE_RDONLY
	tst	ip, #1 << (55 - 32) | 1 << (58 - 32)
	orrne	rl, #PTE_AP2
	biceq	rl, #PTE_AP2

1:	strd	r2, r3, [r0]
	ALT_SMP(W(nop))
	ALT_UP (mcr	p15, 0, r0, c7, c10, 1)		@ flush_pte
#endif
	ret	lr
ENDPROC(cpu_v7_set_pte_ext)

	/*
	 * Memory region attributes for LPAE (defined in pgtable-3level.h):
	 *
	 *   n = AttrIndx[2:0]
	 *
	 *			n	MAIR
	 *   UNCACHED		000	00000000
	 *   BUFFERABLE		001	01000100
	 *   DEV_WC		001	01000100
	 *   WRITETHROUGH	010	10101010
	 *   WRITEBACK		011	11101110
	 *   DEV_CACHED		011	11101110
	 *   DEV_SHARED		100	00000100
	 *   DEV_NONSHARED	100	00000100
	 *   unused		101
	 *   unused		110
	 *   WRITEALLOC		111	11111111
	 */
.equ	PRRR,	0xeeaa4400			@ MAIR0
.equ	NMRR,	0xff000004			@ MAIR1

	/*
	 * Macro for setting up the TTBRx and TTBCR registers.
	 * - \ttbr1 updated.
	 */
	.macro	v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp
	ldr	\tmp, =swapper_pg_dir		@ swapper_pg_dir virtual address
	cmp	\ttbr1, \tmp, lsr #12		@ PHYS_OFFSET > PAGE_OFFSET?
	mov	\tmp, #TTB_EAE			@ for TTB control egister
	ALT_SMP(orr	\tmp, \tmp, #TTB_FLAGS_SMP)
	ALT_UP(orr	\tmp, \tmp, #TTB_FLAGS_UP)
	ALT_SMP(orr	\tmp, \tmp, #TTB_FLAGS_SMP << 16)
	ALT_UP(orr	\tmp, \tmp, #TTB_FLAGS_UP << 16)
	/*
	 * Only use split TTBRs if PHYS_OFFSET <= PAGE_OFFSET (cmp above),
	 * otherwise booting secondary CPUs would end up using TTBR1 for the
	 * identity mapping set up in TTBR0.
	 */
	orrls	\tmp, \tmp, #TTBR1_SIZE				@ TTBCR.T1SZ
	mcr	p15, 0, \tmp, c2, c0, 2				@ TTBCR
	mov	\tmp, \ttbr1, lsr #20
	mov	\ttbr1, \ttbr1, lsl #12
	addls	\ttbr1, \ttbr1, #TTBR1_OFFSET
	mcrr	p15, 1, \ttbr1, \tmp, c2			@ load TTBR1
	.endm

	/*
	 *   AT
	 *  TFR   EV X F   IHD LR    S
	 * .EEE ..EE PUI. .TAT 4RVI ZWRS BLDP WCAM
	 * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
	 *   11    0 110    0  0011 1100 .111 1101 < we want
	 */
	.align	2
	.type	v7_crval, #object
v7_crval:
	crval	clear=0x0122c302, mmuset=0x30c03c7d, ucset=0x00c01c7c


code:
// SPDX-License-Identifier: GPL-2.0
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
#include <linux/smp.h>

#include <asm/cp15.h>
#include <asm/cputype.h>
#include <asm/proc-fns.h>
#include <asm/spectre.h>
#include <asm/system_misc.h>

#ifdef CONFIG_ARM_PSCI
static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
{
	struct arm_smccc_res res;

	arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
			     ARM_SMCCC_ARCH_WORKAROUND_1, &res);

	switch ((int)res.a0) {
	case SMCCC_RET_SUCCESS:
		return SPECTRE_MITIGATED;

	case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
		return SPECTRE_UNAFFECTED;

	default:
		return SPECTRE_VULNERABLE;
	}
}
#else
static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
{
	return SPECTRE_VULNERABLE;
}
#endif

#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);

extern void cpu_v7_iciallu_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
extern void cpu_v7_bpiall_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
extern void cpu_v7_smc_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
extern void cpu_v7_hvc_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);

static void harden_branch_predictor_bpiall(void)
{
	write_sysreg(0, BPIALL);
}

static void harden_branch_predictor_iciallu(void)
{
	write_sysreg(0, ICIALLU);
}

static void __maybe_unused call_smc_arch_workaround_1(void)
{
	arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
}

static void __maybe_unused call_hvc_arch_workaround_1(void)
{
	arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
}

static unsigned int spectre_v2_install_workaround(unsigned int method)
{
	const char *spectre_v2_method = NULL;
	int cpu = smp_processor_id();

	if (per_cpu(harden_branch_predictor_fn, cpu))
		return SPECTRE_MITIGATED;

	switch (method) {
	case SPECTRE_V2_METHOD_BPIALL:
		per_cpu(harden_branch_predictor_fn, cpu) =
			harden_branch_predictor_bpiall;
		spectre_v2_method = "BPIALL";
		break;

	case SPECTRE_V2_METHOD_ICIALLU:
		per_cpu(harden_branch_predictor_fn, cpu) =
			harden_branch_predictor_iciallu;
		spectre_v2_method = "ICIALLU";
		break;

	case SPECTRE_V2_METHOD_HVC:
		per_cpu(harden_branch_predictor_fn, cpu) =
			call_hvc_arch_workaround_1;
		cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
		spectre_v2_method = "hypervisor";
		break;

	case SPECTRE_V2_METHOD_SMC:
		per_cpu(harden_branch_predictor_fn, cpu) =
			call_smc_arch_workaround_1;
		cpu_do_switch_mm = cpu_v7_smc_switch_mm;
		spectre_v2_method = "firmware";
		break;
	}

	if (spectre_v2_method)
		pr_info("CPU%u: Spectre v2: using %s workaround\n",
			smp_processor_id(), spectre_v2_method);

	return SPECTRE_MITIGATED;
}
#else
static unsigned int spectre_v2_install_workaround(unsigned int method)
{
	pr_info_once("Spectre V2: workarounds disabled by configuration\n");

	return SPECTRE_VULNERABLE;
}
#endif

static void cpu_v7_spectre_v2_init(void)
{
	unsigned int state, method = 0;

	switch (read_cpuid_part()) {
	case ARM_CPU_PART_CORTEX_A8:
	case ARM_CPU_PART_CORTEX_A9:
	case ARM_CPU_PART_CORTEX_A12:
	case ARM_CPU_PART_CORTEX_A17:
	case ARM_CPU_PART_CORTEX_A73:
	case ARM_CPU_PART_CORTEX_A75:
		state = SPECTRE_MITIGATED;
		method = SPECTRE_V2_METHOD_BPIALL;
		break;

	case ARM_CPU_PART_CORTEX_A15:
	case ARM_CPU_PART_BRAHMA_B15:
		state = SPECTRE_MITIGATED;
		method = SPECTRE_V2_METHOD_ICIALLU;
		break;

	case ARM_CPU_PART_BRAHMA_B53:
		/* Requires no workaround */
		state = SPECTRE_UNAFFECTED;
		break;

	default:
		/* Other ARM CPUs require no workaround */
		if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) {
			state = SPECTRE_UNAFFECTED;
			break;
		}

		fallthrough;

	/* Cortex A57/A72 require firmware workaround */
	case ARM_CPU_PART_CORTEX_A57:
	case ARM_CPU_PART_CORTEX_A72:
		state = spectre_v2_get_cpu_fw_mitigation_state();
		if (state != SPECTRE_MITIGATED)
			break;

		switch (arm_smccc_1_1_get_conduit()) {
		case SMCCC_CONDUIT_HVC:
			method = SPECTRE_V2_METHOD_HVC;
			break;

		case SMCCC_CONDUIT_SMC:
			method = SPECTRE_V2_METHOD_SMC;
			break;

		default:
			state = SPECTRE_VULNERABLE;
			break;
		}
	}

	if (state == SPECTRE_MITIGATED)
		state = spectre_v2_install_workaround(method);

	spectre_v2_update_state(state, method);
}

#ifdef CONFIG_HARDEN_BRANCH_HISTORY
static int spectre_bhb_method;

static const char *spectre_bhb_method_name(int method)
{
	switch (method) {
	case SPECTRE_V2_METHOD_LOOP8:
		return "loop";

	case SPECTRE_V2_METHOD_BPIALL:
		return "BPIALL";

	default:
		return "unknown";
	}
}

static int spectre_bhb_install_workaround(int method)
{
	if (spectre_bhb_method != method) {
		if (spectre_bhb_method) {
			pr_err("CPU%u: Spectre BHB: method disagreement, system vulnerable\n",
			       smp_processor_id());

			return SPECTRE_VULNERABLE;
		}

		if (spectre_bhb_update_vectors(method) == SPECTRE_VULNERABLE)
			return SPECTRE_VULNERABLE;

		spectre_bhb_method = method;

		pr_info("CPU%u: Spectre BHB: enabling %s workaround for all CPUs\n",
			smp_processor_id(), spectre_bhb_method_name(method));
	}

	return SPECTRE_MITIGATED;
}
#else
static int spectre_bhb_install_workaround(int method)
{
	return SPECTRE_VULNERABLE;
}
#endif

static void cpu_v7_spectre_bhb_init(void)
{
	unsigned int state, method = 0;

	switch (read_cpuid_part()) {
	case ARM_CPU_PART_CORTEX_A15:
	case ARM_CPU_PART_BRAHMA_B15:
	case ARM_CPU_PART_CORTEX_A57:
	case ARM_CPU_PART_CORTEX_A72:
		state = SPECTRE_MITIGATED;
		method = SPECTRE_V2_METHOD_LOOP8;
		break;

	case ARM_CPU_PART_CORTEX_A73:
	case ARM_CPU_PART_CORTEX_A75:
		state = SPECTRE_MITIGATED;
		method = SPECTRE_V2_METHOD_BPIALL;
		break;

	default:
		state = SPECTRE_UNAFFECTED;
		break;
	}

	if (state == SPECTRE_MITIGATED)
		state = spectre_bhb_install_workaround(method);

	spectre_v2_update_state(state, method);
}

static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
						  u32 mask, const char *msg)
{
	u32 aux_cr;

	asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (aux_cr));

	if ((aux_cr & mask) != mask) {
		if (!*warned)
			pr_err("CPU%u: %s", smp_processor_id(), msg);
		*warned = true;
		return false;
	}
	return true;
}

static DEFINE_PER_CPU(bool, spectre_warned);

static bool check_spectre_auxcr(bool *warned, u32 bit)
{
	return IS_ENABLED(CONFIG_HARDEN_BRANCH_PREDICTOR) &&
		cpu_v7_check_auxcr_set(warned, bit,
				       "Spectre v2: firmware did not set auxiliary control register IBE bit, system vulnerable\n");
}

void cpu_v7_ca8_ibe(void)
{
	if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6)))
		cpu_v7_spectre_v2_init();
}

void cpu_v7_ca15_ibe(void)
{
	if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0)))
		cpu_v7_spectre_v2_init();
	cpu_v7_spectre_bhb_init();
}

void cpu_v7_bugs_init(void)
{
	cpu_v7_spectre_v2_init();
	cpu_v7_spectre_bhb_init();
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mm/proc-v7.S
 *
 *  Copyright (C) 2001 Deep Blue Solutions Ltd.
 *
 *  This is the "shell" of the ARMv7 processor support.
 */
#include <linux/arm-smccc.h>
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/pgtable.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hwcap.h>
#include <asm/pgtable-hwdef.h>
#include <asm/memory.h>

#include "proc-macros.S"

#ifdef CONFIG_ARM_LPAE
#include "proc-v7-3level.S"
#else
#include "proc-v7-2level.S"
#endif

.arch armv7-a

ENTRY(cpu_v7_proc_init)
	ret	lr
ENDPROC(cpu_v7_proc_init)

ENTRY(cpu_v7_proc_fin)
	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
	bic	r0, r0, #0x1000			@ ...i............
	bic	r0, r0, #0x0006			@ .............ca.
	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
	ret	lr
ENDPROC(cpu_v7_proc_fin)

/*
 *	cpu_v7_reset(loc, hyp)
 *
 *	Perform a soft reset of the system.  Put the CPU into the
 *	same state as it would be if it had been reset, and branch
 *	to what would be the reset vector.
 *
 *	- loc   - location to jump to for soft reset
 *	- hyp   - indicate if restart occurs in HYP mode
 *
 *	This code must be executed using a flat identity mapping with
 *      caches disabled.
 */
	.align	5
	.pushsection	.idmap.text, "ax"
ENTRY(cpu_v7_reset)
	mrc	p15, 0, r2, c1, c0, 0		@ ctrl register
	bic	r2, r2, #0x1			@ ...............m
 THUMB(	bic	r2, r2, #1 << 30 )		@ SCTLR.TE (Thumb exceptions)
	mcr	p15, 0, r2, c1, c0, 0		@ disable MMU
	isb
#ifdef CONFIG_ARM_VIRT_EXT
	teq	r1, #0
	bne	__hyp_soft_restart
#endif
	bx	r0
ENDPROC(cpu_v7_reset)
	.popsection

/*
 *	cpu_v7_do_idle()
 *
 *	Idle the processor (eg, wait for interrupt).
 *
 *	IRQs are already disabled.
 */
ENTRY(cpu_v7_do_idle)
	dsb					@ WFI may enter a low-power mode
	wfi
	ret	lr
ENDPROC(cpu_v7_do_idle)

ENTRY(cpu_v7_dcache_clean_area)
	ALT_SMP(W(nop))			@ MP extensions imply L1 PTW
	ALT_UP_B(1f)
	ret	lr
1:	dcache_line_size r2, r3
2:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
	add	r0, r0, r2
	subs	r1, r1, r2
	bhi	2b
	dsb	ishst
	ret	lr
ENDPROC(cpu_v7_dcache_clean_area)

#ifdef CONFIG_ARM_PSCI
	.arch_extension sec
ENTRY(cpu_v7_smc_switch_mm)
	stmfd	sp!, {r0 - r3}
	movw	r0, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1
	movt	r0, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1
	smc	#0
	ldmfd	sp!, {r0 - r3}
	b	cpu_v7_switch_mm
ENDPROC(cpu_v7_smc_switch_mm)
	.arch_extension virt
ENTRY(cpu_v7_hvc_switch_mm)
	stmfd	sp!, {r0 - r3}
	movw	r0, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1
	movt	r0, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1
	hvc	#0
	ldmfd	sp!, {r0 - r3}
	b	cpu_v7_switch_mm
ENDPROC(cpu_v7_hvc_switch_mm)
#endif
ENTRY(cpu_v7_iciallu_switch_mm)
	mov	r3, #0
	mcr	p15, 0, r3, c7, c5, 0		@ ICIALLU
	b	cpu_v7_switch_mm
ENDPROC(cpu_v7_iciallu_switch_mm)
ENTRY(cpu_v7_bpiall_switch_mm)
	mov	r3, #0
	mcr	p15, 0, r3, c7, c5, 6		@ flush BTAC/BTB
	b	cpu_v7_switch_mm
ENDPROC(cpu_v7_bpiall_switch_mm)

	string	cpu_v7_name, "ARMv7 Processor"
	.align

/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
.globl	cpu_v7_suspend_size
.equ	cpu_v7_suspend_size, 4 * 9
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_v7_do_suspend)
	stmfd	sp!, {r4 - r11, lr}
	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
	mrc	p15, 0, r5, c13, c0, 3	@ User r/o thread ID
	stmia	r0!, {r4 - r5}
#ifdef CONFIG_MMU
	mrc	p15, 0, r6, c3, c0, 0	@ Domain ID
#ifdef CONFIG_ARM_LPAE
	mrrc	p15, 1, r5, r7, c2	@ TTB 1
#else
	mrc	p15, 0, r7, c2, c0, 1	@ TTB 1
#endif
	mrc	p15, 0, r11, c2, c0, 2	@ TTB control register
#endif
	mrc	p15, 0, r8, c1, c0, 0	@ Control register
	mrc	p15, 0, r9, c1, c0, 1	@ Auxiliary control register
	mrc	p15, 0, r10, c1, c0, 2	@ Co-processor access control
	stmia	r0, {r5 - r11}
	ldmfd	sp!, {r4 - r11, pc}
ENDPROC(cpu_v7_do_suspend)

ENTRY(cpu_v7_do_resume)
	mov	ip, #0
	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
	ldmia	r0!, {r4 - r5}
	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
	mcr	p15, 0, r5, c13, c0, 3	@ User r/o thread ID
	ldmia	r0, {r5 - r11}
#ifdef CONFIG_MMU
	mcr	p15, 0, ip, c8, c7, 0	@ invalidate TLBs
	mcr	p15, 0, r6, c3, c0, 0	@ Domain ID
#ifdef CONFIG_ARM_LPAE
	mcrr	p15, 0, r1, ip, c2	@ TTB 0
	mcrr	p15, 1, r5, r7, c2	@ TTB 1
#else
	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
	ALT_UP(orr	r1, r1, #TTB_FLAGS_UP)
	mcr	p15, 0, r1, c2, c0, 0	@ TTB 0
	mcr	p15, 0, r7, c2, c0, 1	@ TTB 1
#endif
	mcr	p15, 0, r11, c2, c0, 2	@ TTB control register
	ldr	r4, =PRRR		@ PRRR
	ldr	r5, =NMRR		@ NMRR
	mcr	p15, 0, r4, c10, c2, 0	@ write PRRR
	mcr	p15, 0, r5, c10, c2, 1	@ write NMRR
#endif	/* CONFIG_MMU */
	mrc	p15, 0, r4, c1, c0, 1	@ Read Auxiliary control register
	teq	r4, r9			@ Is it already set?
	mcrne	p15, 0, r9, c1, c0, 1	@ No, so write it
	mcr	p15, 0, r10, c1, c0, 2	@ Co-processor access control
	isb
	dsb
	mov	r0, r8			@ control register
	b	cpu_resume_mmu
ENDPROC(cpu_v7_do_resume)
#endif

.globl	cpu_ca9mp_suspend_size
.equ	cpu_ca9mp_suspend_size, cpu_v7_suspend_size + 4 * 2
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_ca9mp_do_suspend)
	stmfd	sp!, {r4 - r5}
	mrc	p15, 0, r4, c15, c0, 1		@ Diagnostic register
	mrc	p15, 0, r5, c15, c0, 0		@ Power register
	stmia	r0!, {r4 - r5}
	ldmfd	sp!, {r4 - r5}
	b	cpu_v7_do_suspend
ENDPROC(cpu_ca9mp_do_suspend)

ENTRY(cpu_ca9mp_do_resume)
	ldmia	r0!, {r4 - r5}
	mrc	p15, 0, r10, c15, c0, 1		@ Read Diagnostic register
	teq	r4, r10				@ Already restored?
	mcrne	p15, 0, r4, c15, c0, 1		@ No, so restore it
	mrc	p15, 0, r10, c15, c0, 0		@ Read Power register
	teq	r5, r10				@ Already restored?
	mcrne	p15, 0, r5, c15, c0, 0		@ No, so restore it
	b	cpu_v7_do_resume
ENDPROC(cpu_ca9mp_do_resume)
#endif

#ifdef CONFIG_CPU_PJ4B
	globl_equ	cpu_pj4b_switch_mm,     cpu_v7_switch_mm
	globl_equ	cpu_pj4b_set_pte_ext,	cpu_v7_set_pte_ext
	globl_equ	cpu_pj4b_proc_init,	cpu_v7_proc_init
	globl_equ	cpu_pj4b_proc_fin, 	cpu_v7_proc_fin
	globl_equ	cpu_pj4b_reset,	   	cpu_v7_reset
#ifdef CONFIG_PJ4B_ERRATA_4742
ENTRY(cpu_pj4b_do_idle)
	dsb					@ WFI may enter a low-power mode
	wfi
	dsb					@barrier
	ret	lr
ENDPROC(cpu_pj4b_do_idle)
#else
	globl_equ	cpu_pj4b_do_idle,  	cpu_v7_do_idle
#endif
	globl_equ	cpu_pj4b_dcache_clean_area,	cpu_v7_dcache_clean_area
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_pj4b_do_suspend)
	stmfd	sp!, {r6 - r10}
	mrc	p15, 1, r6, c15, c1, 0  @ save CP15 - extra features
	mrc	p15, 1, r7, c15, c2, 0	@ save CP15 - Aux Func Modes Ctrl 0
	mrc	p15, 1, r8, c15, c1, 2	@ save CP15 - Aux Debug Modes Ctrl 2
	mrc	p15, 1, r9, c15, c1, 1  @ save CP15 - Aux Debug Modes Ctrl 1
	mrc	p15, 0, r10, c9, c14, 0  @ save CP15 - PMC
	stmia	r0!, {r6 - r10}
	ldmfd	sp!, {r6 - r10}
	b cpu_v7_do_suspend
ENDPROC(cpu_pj4b_do_suspend)

ENTRY(cpu_pj4b_do_resume)
	ldmia	r0!, {r6 - r10}
	mcr	p15, 1, r6, c15, c1, 0  @ restore CP15 - extra features
	mcr	p15, 1, r7, c15, c2, 0	@ restore CP15 - Aux Func Modes Ctrl 0
	mcr	p15, 1, r8, c15, c1, 2	@ restore CP15 - Aux Debug Modes Ctrl 2
	mcr	p15, 1, r9, c15, c1, 1  @ restore CP15 - Aux Debug Modes Ctrl 1
	mcr	p15, 0, r10, c9, c14, 0  @ restore CP15 - PMC
	b cpu_v7_do_resume
ENDPROC(cpu_pj4b_do_resume)
#endif
.globl	cpu_pj4b_suspend_size
.equ	cpu_pj4b_suspend_size, cpu_v7_suspend_size + 4 * 5

#endif

	@
	@ Invoke the v7_invalidate_l1() function, which adheres to the AAPCS
	@ rules, and so it may corrupt registers that we need to preserve.
	@
	.macro	do_invalidate_l1
	mov	r6, r1
	mov	r7, r2
	mov	r10, lr
	bl	v7_invalidate_l1		@ corrupts {r0-r3, ip, lr}
	mov	r1, r6
	mov	r2, r7
	mov	lr, r10
	.endm

/*
 *	__v7_setup
 *
 *	Initialise TLB, Caches, and MMU state ready to switch the MMU
 *	on.  Return in r0 the new CP15 C1 control register setting.
 *
 *	r1, r2, r4, r5, r9, r13 must be preserved - r13 is not a stack
 *	r4: TTBR0 (low word)
 *	r5: TTBR0 (high word if LPAE)
 *	r8: TTBR1
 *	r9: Main ID register
 *
 *	This should be able to cover all ARMv7 cores.
 *
 *	It is assumed that:
 *	- cache type register is implemented
 */
__v7_ca5mp_setup:
__v7_ca9mp_setup:
__v7_cr7mp_setup:
__v7_cr8mp_setup:
	do_invalidate_l1
	mov	r10, #(1 << 0)			@ Cache/TLB ops broadcasting
	b	1f
__v7_ca7mp_setup:
__v7_ca12mp_setup:
__v7_ca15mp_setup:
__v7_b15mp_setup:
__v7_ca17mp_setup:
	do_invalidate_l1
	mov	r10, #0
1:
#ifdef CONFIG_SMP
	orr	r10, r10, #(1 << 6)		@ Enable SMP/nAMP mode
	ALT_SMP(mrc	p15, 0, r0, c1, c0, 1)
	ALT_UP(mov	r0, r10)		@ fake it for UP
	orr	r10, r10, r0			@ Set required bits
	teq	r10, r0				@ Were they already set?
	mcrne	p15, 0, r10, c1, c0, 1		@ No, update register
#endif
	b	__v7_setup_cont

/*
 * Errata:
 *  r0, r10 available for use
 *  r1, r2, r4, r5, r9, r13: must be preserved
 *  r3: contains MIDR rX number in bits 23-20
 *  r6: contains MIDR rXpY as 8-bit XY number
 *  r9: MIDR
 */
__ca8_errata:
#if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM)
	teq	r3, #0x00100000			@ only present in r1p*
	mrceq	p15, 0, r0, c1, c0, 1		@ read aux control register
	orreq	r0, r0, #(1 << 6)		@ set IBE to 1
	mcreq	p15, 0, r0, c1, c0, 1		@ write aux control register
#endif
#ifdef CONFIG_ARM_ERRATA_458693
	teq	r6, #0x20			@ only present in r2p0
	mrceq	p15, 0, r0, c1, c0, 1		@ read aux control register
	orreq	r0, r0, #(1 << 5)		@ set L1NEON to 1
	orreq	r0, r0, #(1 << 9)		@ set PLDNOP to 1
	mcreq	p15, 0, r0, c1, c0, 1		@ write aux control register
#endif
#ifdef CONFIG_ARM_ERRATA_460075
	teq	r6, #0x20			@ only present in r2p0
	mrceq	p15, 1, r0, c9, c0, 2		@ read L2 cache aux ctrl register
	tsteq	r0, #1 << 22
	orreq	r0, r0, #(1 << 22)		@ set the Write Allocate disable bit
	mcreq	p15, 1, r0, c9, c0, 2		@ write the L2 cache aux ctrl register
#endif
	b	__errata_finish

__ca9_errata:
#ifdef CONFIG_ARM_ERRATA_742230
	cmp	r6, #0x22			@ only present up to r2p2
	mrcle	p15, 0, r0, c15, c0, 1		@ read diagnostic register
	orrle	r0, r0, #1 << 4			@ set bit #4
	mcrle	p15, 0, r0, c15, c0, 1		@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_742231
	teq	r6, #0x20			@ present in r2p0
	teqne	r6, #0x21			@ present in r2p1
	teqne	r6, #0x22			@ present in r2p2
	mrceq	p15, 0, r0, c15, c0, 1		@ read diagnostic register
	orreq	r0, r0, #1 << 12		@ set bit #12
	orreq	r0, r0, #1 << 22		@ set bit #22
	mcreq	p15, 0, r0, c15, c0, 1		@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_743622
	teq	r3, #0x00200000			@ only present in r2p*
	mrceq	p15, 0, r0, c15, c0, 1		@ read diagnostic register
	orreq	r0, r0, #1 << 6			@ set bit #6
	mcreq	p15, 0, r0, c15, c0, 1		@ write diagnostic register
#endif
#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
	ALT_SMP(cmp r6, #0x30)			@ present prior to r3p0
	ALT_UP_B(1f)
	mrclt	p15, 0, r0, c15, c0, 1		@ read diagnostic register
	orrlt	r0, r0, #1 << 11		@ set bit #11
	mcrlt	p15, 0, r0, c15, c0, 1		@ write diagnostic register
1:
#endif
	b	__errata_finish

__ca15_errata:
#ifdef CONFIG_ARM_ERRATA_773022
	cmp	r6, #0x4			@ only present up to r0p4
	mrcle	p15, 0, r0, c1, c0, 1		@ read aux control register
	orrle	r0, r0, #1 << 1			@ disable loop buffer
	mcrle	p15, 0, r0, c1, c0, 1		@ write aux control register
#endif
	b	__errata_finish

__ca12_errata:
#ifdef CONFIG_ARM_ERRATA_818325_852422
	mrc	p15, 0, r10, c15, c0, 1		@ read diagnostic register
	orr	r10, r10, #1 << 12		@ set bit #12
	mcr	p15, 0, r10, c15, c0, 1		@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_821420
	mrc	p15, 0, r10, c15, c0, 2		@ read internal feature reg
	orr	r10, r10, #1 << 1		@ set bit #1
	mcr	p15, 0, r10, c15, c0, 2		@ write internal feature reg
#endif
#ifdef CONFIG_ARM_ERRATA_825619
	mrc	p15, 0, r10, c15, c0, 1		@ read diagnostic register
	orr	r10, r10, #1 << 24		@ set bit #24
	mcr	p15, 0, r10, c15, c0, 1		@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_857271
	mrc	p15, 0, r10, c15, c0, 1		@ read diagnostic register
	orr	r10, r10, #3 << 10		@ set bits #10 and #11
	mcr	p15, 0, r10, c15, c0, 1		@ write diagnostic register
#endif
	b	__errata_finish

__ca17_errata:
#ifdef CONFIG_ARM_ERRATA_852421
	cmp	r6, #0x12			@ only present up to r1p2
	mrcle	p15, 0, r10, c15, c0, 1		@ read diagnostic register
	orrle	r10, r10, #1 << 24		@ set bit #24
	mcrle	p15, 0, r10, c15, c0, 1		@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_852423
	cmp	r6, #0x12			@ only present up to r1p2
	mrcle	p15, 0, r10, c15, c0, 1		@ read diagnostic register
	orrle	r10, r10, #1 << 12		@ set bit #12
	mcrle	p15, 0, r10, c15, c0, 1		@ write diagnostic register
#endif
#ifdef CONFIG_ARM_ERRATA_857272
	mrc	p15, 0, r10, c15, c0, 1		@ read diagnostic register
	orr	r10, r10, #3 << 10		@ set bits #10 and #11
	mcr	p15, 0, r10, c15, c0, 1		@ write diagnostic register
#endif
	b	__errata_finish

__v7_pj4b_setup:
#ifdef CONFIG_CPU_PJ4B

/* Auxiliary Debug Modes Control 1 Register */
#define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */
#define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */
#define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */

/* Auxiliary Debug Modes Control 2 Register */
#define PJ4B_FAST_LDR (1 << 23) /* Disable fast LDR */
#define PJ4B_SNOOP_DATA (1 << 25) /* Do not interleave write and snoop data */
#define PJ4B_CWF (1 << 27) /* Disable Critical Word First feature */
#define PJ4B_OUTSDNG_NC (1 << 29) /* Disable outstanding non cacheable rqst */
#define PJ4B_L1_REP_RR (1 << 30) /* L1 replacement - Strict round robin */
#define PJ4B_AUX_DBG_CTRL2 (PJ4B_SNOOP_DATA | PJ4B_CWF |\
			    PJ4B_OUTSDNG_NC | PJ4B_L1_REP_RR)

/* Auxiliary Functional Modes Control Register 0 */
#define PJ4B_SMP_CFB (1 << 1) /* Set SMP mode. Join the coherency fabric */
#define PJ4B_L1_PAR_CHK (1 << 2) /* Support L1 parity checking */
#define PJ4B_BROADCAST_CACHE (1 << 8) /* Broadcast Cache and TLB maintenance */

/* Auxiliary Debug Modes Control 0 Register */
#define PJ4B_WFI_WFE (1 << 22) /* WFI/WFE - serve the DVM and back to idle */

	/* Auxiliary Debug Modes Control 1 Register */
	mrc	p15, 1,	r0, c15, c1, 1
	orr     r0, r0, #PJ4B_CLEAN_LINE
	orr     r0, r0, #PJ4B_INTER_PARITY
	bic	r0, r0, #PJ4B_STATIC_BP
	mcr	p15, 1,	r0, c15, c1, 1

	/* Auxiliary Debug Modes Control 2 Register */
	mrc	p15, 1,	r0, c15, c1, 2
	bic	r0, r0, #PJ4B_FAST_LDR
	orr	r0, r0, #PJ4B_AUX_DBG_CTRL2
	mcr	p15, 1,	r0, c15, c1, 2

	/* Auxiliary Functional Modes Control Register 0 */
	mrc	p15, 1,	r0, c15, c2, 0
#ifdef CONFIG_SMP
	orr	r0, r0, #PJ4B_SMP_CFB
#endif
	orr	r0, r0, #PJ4B_L1_PAR_CHK
	orr	r0, r0, #PJ4B_BROADCAST_CACHE
	mcr	p15, 1,	r0, c15, c2, 0

	/* Auxiliary Debug Modes Control 0 Register */
	mrc	p15, 1,	r0, c15, c1, 0
	orr	r0, r0, #PJ4B_WFI_WFE
	mcr	p15, 1,	r0, c15, c1, 0

#endif /* CONFIG_CPU_PJ4B */

__v7_setup:
	do_invalidate_l1

__v7_setup_cont:
	and	r0, r9, #0xff000000		@ ARM?
	teq	r0, #0x41000000
	bne	__errata_finish
	and	r3, r9, #0x00f00000		@ variant
	and	r6, r9, #0x0000000f		@ revision
	orr	r6, r6, r3, lsr #20-4		@ combine variant and revision
	ubfx	r0, r9, #4, #12			@ primary part number

	/* Cortex-A8 Errata */
	ldr	r10, =0x00000c08		@ Cortex-A8 primary part number
	teq	r0, r10
	beq	__ca8_errata

	/* Cortex-A9 Errata */
	ldr	r10, =0x00000c09		@ Cortex-A9 primary part number
	teq	r0, r10
	beq	__ca9_errata

	/* Cortex-A12 Errata */
	ldr	r10, =0x00000c0d		@ Cortex-A12 primary part number
	teq	r0, r10
	beq	__ca12_errata

	/* Cortex-A17 Errata */
	ldr	r10, =0x00000c0e		@ Cortex-A17 primary part number
	teq	r0, r10
	beq	__ca17_errata

	/* Cortex-A15 Errata */
	ldr	r10, =0x00000c0f		@ Cortex-A15 primary part number
	teq	r0, r10
	beq	__ca15_errata

__errata_finish:
	mov	r10, #0
	mcr	p15, 0, r10, c7, c5, 0		@ I+BTB cache invalidate
#ifdef CONFIG_MMU
	mcr	p15, 0, r10, c8, c7, 0		@ invalidate I + D TLBs
	v7_ttb_setup r10, r4, r5, r8, r3	@ TTBCR, TTBRx setup
	ldr	r3, =PRRR			@ PRRR
	ldr	r6, =NMRR			@ NMRR
	mcr	p15, 0, r3, c10, c2, 0		@ write PRRR
	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
#endif
	dsb					@ Complete invalidations
#ifndef CONFIG_ARM_THUMBEE
	mrc	p15, 0, r0, c0, c1, 0		@ read ID_PFR0 for ThumbEE
	and	r0, r0, #(0xf << 12)		@ ThumbEE enabled field
	teq	r0, #(1 << 12)			@ check if ThumbEE is present
	bne	1f
	mov	r3, #0
	mcr	p14, 6, r3, c1, c0, 0		@ Initialize TEEHBR to 0
	mrc	p14, 6, r0, c0, c0, 0		@ load TEECR
	orr	r0, r0, #1			@ set the 1st bit in order to
	mcr	p14, 6, r0, c0, c0, 0		@ stop userspace TEEHBR access
1:
#endif
	adr	r3, v7_crval
	ldmia	r3, {r3, r6}
 ARM_BE8(orr	r6, r6, #1 << 25)		@ big-endian page tables
#ifdef CONFIG_SWP_EMULATE
	orr     r3, r3, #(1 << 10)              @ set SW bit in "clear"
	bic     r6, r6, #(1 << 10)              @ clear it in "mmuset"
#endif
   	mrc	p15, 0, r0, c1, c0, 0		@ read control register
	bic	r0, r0, r3			@ clear bits them
	orr	r0, r0, r6			@ set them
 THUMB(	orr	r0, r0, #1 << 30	)	@ Thumb exceptions
	ret	lr				@ return to head.S:__ret
ENDPROC(__v7_setup)

	__INITDATA

	.weak cpu_v7_bugs_init

	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
	define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init

#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
	@ generic v7 bpiall on context switch
	globl_equ	cpu_v7_bpiall_proc_init,	cpu_v7_proc_init
	globl_equ	cpu_v7_bpiall_proc_fin,		cpu_v7_proc_fin
	globl_equ	cpu_v7_bpiall_reset,		cpu_v7_reset
	globl_equ	cpu_v7_bpiall_do_idle,		cpu_v7_do_idle
	globl_equ	cpu_v7_bpiall_dcache_clean_area, cpu_v7_dcache_clean_area
	globl_equ	cpu_v7_bpiall_set_pte_ext,	cpu_v7_set_pte_ext
	globl_equ	cpu_v7_bpiall_suspend_size,	cpu_v7_suspend_size
#ifdef CONFIG_ARM_CPU_SUSPEND
	globl_equ	cpu_v7_bpiall_do_suspend,	cpu_v7_do_suspend
	globl_equ	cpu_v7_bpiall_do_resume,	cpu_v7_do_resume
#endif
	define_processor_functions v7_bpiall, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init

#define HARDENED_BPIALL_PROCESSOR_FUNCTIONS v7_bpiall_processor_functions
#else
#define HARDENED_BPIALL_PROCESSOR_FUNCTIONS v7_processor_functions
#endif

#ifndef CONFIG_ARM_LPAE
	@ Cortex-A8 - always needs bpiall switch_mm implementation
	globl_equ	cpu_ca8_proc_init,	cpu_v7_proc_init
	globl_equ	cpu_ca8_proc_fin,	cpu_v7_proc_fin
	globl_equ	cpu_ca8_reset,		cpu_v7_reset
	globl_equ	cpu_ca8_do_idle,	cpu_v7_do_idle
	globl_equ	cpu_ca8_dcache_clean_area, cpu_v7_dcache_clean_area
	globl_equ	cpu_ca8_set_pte_ext,	cpu_v7_set_pte_ext
	globl_equ	cpu_ca8_switch_mm,	cpu_v7_bpiall_switch_mm
	globl_equ	cpu_ca8_suspend_size,	cpu_v7_suspend_size
#ifdef CONFIG_ARM_CPU_SUSPEND
	globl_equ	cpu_ca8_do_suspend,	cpu_v7_do_suspend
	globl_equ	cpu_ca8_do_resume,	cpu_v7_do_resume
#endif
	define_processor_functions ca8, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_ca8_ibe

	@ Cortex-A9 - needs more registers preserved across suspend/resume
	@ and bpiall switch_mm for hardening
	globl_equ	cpu_ca9mp_proc_init,	cpu_v7_proc_init
	globl_equ	cpu_ca9mp_proc_fin,	cpu_v7_proc_fin
	globl_equ	cpu_ca9mp_reset,	cpu_v7_reset
	globl_equ	cpu_ca9mp_do_idle,	cpu_v7_do_idle
	globl_equ	cpu_ca9mp_dcache_clean_area, cpu_v7_dcache_clean_area
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_bpiall_switch_mm
#else
	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_switch_mm
#endif
	globl_equ	cpu_ca9mp_set_pte_ext,	cpu_v7_set_pte_ext
	define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_bugs_init
#endif

	@ Cortex-A15 - needs iciallu switch_mm for hardening
	globl_equ	cpu_ca15_proc_init,	cpu_v7_proc_init
	globl_equ	cpu_ca15_proc_fin,	cpu_v7_proc_fin
	globl_equ	cpu_ca15_reset,		cpu_v7_reset
	globl_equ	cpu_ca15_do_idle,	cpu_v7_do_idle
	globl_equ	cpu_ca15_dcache_clean_area, cpu_v7_dcache_clean_area
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
	globl_equ	cpu_ca15_switch_mm,	cpu_v7_iciallu_switch_mm
#else
	globl_equ	cpu_ca15_switch_mm,	cpu_v7_switch_mm
#endif
	globl_equ	cpu_ca15_set_pte_ext,	cpu_v7_set_pte_ext
	globl_equ	cpu_ca15_suspend_size,	cpu_v7_suspend_size
	globl_equ	cpu_ca15_do_suspend,	cpu_v7_do_suspend
	globl_equ	cpu_ca15_do_resume,	cpu_v7_do_resume
	define_processor_functions ca15, dabort=v7_early_abort, pabort=v7_pabort, suspend=1, bugs=cpu_v7_ca15_ibe
#ifdef CONFIG_CPU_PJ4B
	define_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
#endif

	.section ".rodata"

	string	cpu_arch_name, "armv7"
	string	cpu_elf_name, "v7"
	.align

	.section ".proc.info.init", "a"

	/*
	 * Standard v7 proc info content
	 */
.macro __v7_proc name, initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions, cache_fns = v7_cache_fns
	ALT_SMP(.long	PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
			PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)
	ALT_UP(.long	PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
			PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags)
	.long	PMD_TYPE_SECT | PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflags
	initfn	\initfunc, \name
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \
		HWCAP_EDSP | HWCAP_TLS | \hwcaps
	.long	cpu_v7_name
	.long	\proc_fns
	.long	v7wbi_tlb_fns
	.long	v6_user_fns
	.long	\cache_fns
.endm

#ifndef CONFIG_ARM_LPAE
	/*
	 * ARM Ltd. Cortex A5 processor.
	 */
	.type   __v7_ca5mp_proc_info, #object
__v7_ca5mp_proc_info:
	.long	0x410fc050
	.long	0xff0ffff0
	__v7_proc __v7_ca5mp_proc_info, __v7_ca5mp_setup
	.size	__v7_ca5mp_proc_info, . - __v7_ca5mp_proc_info

	/*
	 * ARM Ltd. Cortex A9 processor.
	 */
	.type   __v7_ca9mp_proc_info, #object
__v7_ca9mp_proc_info:
	.long	0x410fc090
	.long	0xff0ffff0
	__v7_proc __v7_ca9mp_proc_info, __v7_ca9mp_setup, proc_fns = ca9mp_processor_functions
	.size	__v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info

	/*
	 * ARM Ltd. Cortex A8 processor.
	 */
	.type	__v7_ca8_proc_info, #object
__v7_ca8_proc_info:
	.long	0x410fc080
	.long	0xff0ffff0
	__v7_proc __v7_ca8_proc_info, __v7_setup, proc_fns = ca8_processor_functions
	.size	__v7_ca8_proc_info, . - __v7_ca8_proc_info

#endif	/* CONFIG_ARM_LPAE */

	/*
	 * Marvell PJ4B processor.
	 */
#ifdef CONFIG_CPU_PJ4B
	.type   __v7_pj4b_proc_info, #object
__v7_pj4b_proc_info:
	.long	0x560f5800
	.long	0xff0fff00
	__v7_proc __v7_pj4b_proc_info, __v7_pj4b_setup, proc_fns = pj4b_processor_functions
	.size	__v7_pj4b_proc_info, . - __v7_pj4b_proc_info
#endif

	/*
	 * ARM Ltd. Cortex R7 processor.
	 */
	.type	__v7_cr7mp_proc_info, #object
__v7_cr7mp_proc_info:
	.long	0x410fc170
	.long	0xff0ffff0
	__v7_proc __v7_cr7mp_proc_info, __v7_cr7mp_setup
	.size	__v7_cr7mp_proc_info, . - __v7_cr7mp_proc_info

	/*
	 * ARM Ltd. Cortex R8 processor.
	 */
	.type	__v7_cr8mp_proc_info, #object
__v7_cr8mp_proc_info:
	.long	0x410fc180
	.long	0xff0ffff0
	__v7_proc __v7_cr8mp_proc_info, __v7_cr8mp_setup
	.size	__v7_cr8mp_proc_info, . - __v7_cr8mp_proc_info

	/*
	 * ARM Ltd. Cortex A7 processor.
	 */
	.type	__v7_ca7mp_proc_info, #object
__v7_ca7mp_proc_info:
	.long	0x410fc070
	.long	0xff0ffff0
	__v7_proc __v7_ca7mp_proc_info, __v7_ca7mp_setup
	.size	__v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info

	/*
	 * ARM Ltd. Cortex A12 processor.
	 */
	.type	__v7_ca12mp_proc_info, #object
__v7_ca12mp_proc_info:
	.long	0x410fc0d0
	.long	0xff0ffff0
	__v7_proc __v7_ca12mp_proc_info, __v7_ca12mp_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
	.size	__v7_ca12mp_proc_info, . - __v7_ca12mp_proc_info

	/*
	 * ARM Ltd. Cortex A15 processor.
	 */
	.type	__v7_ca15mp_proc_info, #object
__v7_ca15mp_proc_info:
	.long	0x410fc0f0
	.long	0xff0ffff0
	__v7_proc __v7_ca15mp_proc_info, __v7_ca15mp_setup, proc_fns = ca15_processor_functions
	.size	__v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info

	/*
	 * Broadcom Corporation Brahma-B15 processor.
	 */
	.type	__v7_b15mp_proc_info, #object
__v7_b15mp_proc_info:
	.long	0x420f00f0
	.long	0xff0ffff0
	__v7_proc __v7_b15mp_proc_info, __v7_b15mp_setup, proc_fns = ca15_processor_functions, cache_fns = b15_cache_fns
	.size	__v7_b15mp_proc_info, . - __v7_b15mp_proc_info

	/*
	 * ARM Ltd. Cortex A17 processor.
	 */
	.type	__v7_ca17mp_proc_info, #object
__v7_ca17mp_proc_info:
	.long	0x410fc0e0
	.long	0xff0ffff0
	__v7_proc __v7_ca17mp_proc_info, __v7_ca17mp_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
	.size	__v7_ca17mp_proc_info, . - __v7_ca17mp_proc_info

	/* ARM Ltd. Cortex A73 processor */
	.type	__v7_ca73_proc_info, #object
__v7_ca73_proc_info:
	.long	0x410fd090
	.long	0xff0ffff0
	__v7_proc __v7_ca73_proc_info, __v7_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
	.size	__v7_ca73_proc_info, . - __v7_ca73_proc_info

	/* ARM Ltd. Cortex A75 processor */
	.type	__v7_ca75_proc_info, #object
__v7_ca75_proc_info:
	.long	0x410fd0a0
	.long	0xff0ffff0
	__v7_proc __v7_ca75_proc_info, __v7_setup, proc_fns = HARDENED_BPIALL_PROCESSOR_FUNCTIONS
	.size	__v7_ca75_proc_info, . - __v7_ca75_proc_info

	/*
	 * Qualcomm Inc. Krait processors.
	 */
	.type	__krait_proc_info, #object
__krait_proc_info:
	.long	0x510f0400		@ Required ID value
	.long	0xff0ffc00		@ Mask for ID
	/*
	 * Some Krait processors don't indicate support for SDIV and UDIV
	 * instructions in the ARM instruction set, even though they actually
	 * do support them. They also don't indicate support for fused multiply
	 * instructions even though they actually do support them.
	 */
	__v7_proc __krait_proc_info, __v7_setup, hwcaps = HWCAP_IDIV | HWCAP_VFPv4
	.size	__krait_proc_info, . - __krait_proc_info

	/*
	 * Match any ARMv7 processor core.
	 */
	.type	__v7_proc_info, #object
__v7_proc_info:
	.long	0x000f0000		@ Required ID value
	.long	0x000f0000		@ Mask for ID
	__v7_proc __v7_proc_info, __v7_setup
	.size	__v7_proc_info, . - __v7_proc_info


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mm/proc-v7m.S
 *
 *  Copyright (C) 2008 ARM Ltd.
 *  Copyright (C) 2001 Deep Blue Solutions Ltd.
 *
 *  This is the "shell" of the ARMv7-M processor support.
 */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/memory.h>
#include <asm/v7m.h>
#include "proc-macros.S"

ENTRY(cpu_v7m_proc_init)
	ret	lr
ENDPROC(cpu_v7m_proc_init)

ENTRY(cpu_v7m_proc_fin)
	ret	lr
ENDPROC(cpu_v7m_proc_fin)

/*
 *	cpu_v7m_reset(loc)
 *
 *	Perform a soft reset of the system.  Put the CPU into the
 *	same state as it would be if it had been reset, and branch
 *	to what would be the reset vector.
 *
 *	- loc   - location to jump to for soft reset
 */
	.align	5
ENTRY(cpu_v7m_reset)
	ret	r0
ENDPROC(cpu_v7m_reset)

/*
 *	cpu_v7m_do_idle()
 *
 *	Idle the processor (eg, wait for interrupt).
 *
 *	IRQs are already disabled.
 */
ENTRY(cpu_v7m_do_idle)
	wfi
	ret	lr
ENDPROC(cpu_v7m_do_idle)

ENTRY(cpu_v7m_dcache_clean_area)
	ret	lr
ENDPROC(cpu_v7m_dcache_clean_area)

/*
 * There is no MMU, so here is nothing to do.
 */
ENTRY(cpu_v7m_switch_mm)
	ret	lr
ENDPROC(cpu_v7m_switch_mm)

.globl	cpu_v7m_suspend_size
.equ	cpu_v7m_suspend_size, 0

#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_v7m_do_suspend)
	ret	lr
ENDPROC(cpu_v7m_do_suspend)

ENTRY(cpu_v7m_do_resume)
	ret	lr
ENDPROC(cpu_v7m_do_resume)
#endif

ENTRY(cpu_cm7_dcache_clean_area)
	dcache_line_size r2, r3
	movw	r3, #:lower16:BASEADDR_V7M_SCB + V7M_SCB_DCCMVAC
	movt	r3, #:upper16:BASEADDR_V7M_SCB + V7M_SCB_DCCMVAC

1:	str	r0, [r3]		@ clean D entry
	add	r0, r0, r2
	subs	r1, r1, r2
	bhi	1b
	dsb
	ret	lr
ENDPROC(cpu_cm7_dcache_clean_area)

ENTRY(cpu_cm7_proc_fin)
	movw	r2, #:lower16:(BASEADDR_V7M_SCB + V7M_SCB_CCR)
	movt	r2, #:upper16:(BASEADDR_V7M_SCB + V7M_SCB_CCR)
	ldr	r0, [r2]
	bic	r0, r0, #(V7M_SCB_CCR_DC | V7M_SCB_CCR_IC)
	str	r0, [r2]
	ret	lr
ENDPROC(cpu_cm7_proc_fin)

	.section ".init.text", "ax"

__v7m_cm7_setup:
	mov	r8, #(V7M_SCB_CCR_DC | V7M_SCB_CCR_IC| V7M_SCB_CCR_BP)
	b	__v7m_setup_cont
/*
 *	__v7m_setup
 *
 *	This should be able to cover all ARMv7-M cores.
 */
__v7m_setup:
	mov	r8, 0

__v7m_setup_cont:
	@ Configure the vector table base address
	ldr	r0, =BASEADDR_V7M_SCB
	ldr	r12, =vector_table
	str	r12, [r0, V7M_SCB_VTOR]

	@ enable UsageFault, BusFault and MemManage fault.
	ldr	r5, [r0, #V7M_SCB_SHCSR]
	orr	r5, #(V7M_SCB_SHCSR_USGFAULTENA | V7M_SCB_SHCSR_BUSFAULTENA | V7M_SCB_SHCSR_MEMFAULTENA)
	str	r5, [r0, #V7M_SCB_SHCSR]

	@ Lower the priority of the SVC and PendSV exceptions
	mov	r5, #0x80000000
	str	r5, [r0, V7M_SCB_SHPR2]	@ set SVC priority
	mov	r5, #0x00800000
	str	r5, [r0, V7M_SCB_SHPR3]	@ set PendSV priority

	@ SVC to switch to handler mode. Notice that this requires sp to
	@ point to writeable memory because the processor saves
	@ some registers to the stack.
	badr	r1, 1f
	ldr	r5, [r12, #11 * 4]	@ read the SVC vector entry
	str	r1, [r12, #11 * 4]	@ write the temporary SVC vector entry
	dsb
	mov	r6, lr			@ save LR
	ldr	sp, =init_thread_union + THREAD_START_SP
	cpsie	i
	svc	#0
1:	cpsid	i
	/* Calculate exc_ret */
	orr	r10, lr, #EXC_RET_THREADMODE_PROCESSSTACK
	ldmia	sp, {r0-r3, r12}
	str	r5, [r12, #11 * 4]	@ restore the original SVC vector entry
	mov	lr, r6			@ restore LR

	@ Special-purpose control register
	mov	r1, #1
	msr	control, r1		@ Thread mode has unpriviledged access

	@ Configure caches (if implemented)
	teq     r8, #0
	stmiane	sp, {r0-r6, lr}		@ v7m_invalidate_l1 touches r0-r6
	blne	v7m_invalidate_l1
	teq     r8, #0			@ re-evalutae condition
	ldmiane	sp, {r0-r6, lr}

	@ Configure the System Control Register to ensure 8-byte stack alignment
	@ Note the STKALIGN bit is either RW or RAO.
	ldr	r0, [r0, V7M_SCB_CCR]   @ system control register
	orr	r0, #V7M_SCB_CCR_STKALIGN
	orr	r0, r0, r8

	ret	lr
ENDPROC(__v7m_setup)

/*
 * Cortex-M7 processor functions
 */
	globl_equ	cpu_cm7_proc_init,	cpu_v7m_proc_init
	globl_equ	cpu_cm7_reset,		cpu_v7m_reset
	globl_equ	cpu_cm7_do_idle,	cpu_v7m_do_idle
	globl_equ	cpu_cm7_switch_mm,	cpu_v7m_switch_mm

	define_processor_functions v7m, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
	define_processor_functions cm7, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1

	.section ".rodata"
	string cpu_arch_name, "armv7m"
	string cpu_elf_name "v7m"
	string cpu_v7m_name "ARMv7-M"

	.section ".proc.info.init", "a"

.macro __v7m_proc name, initfunc, cache_fns = nop_cache_fns, hwcaps = 0,  proc_fns = v7m_processor_functions
	.long	0			/* proc_info_list.__cpu_mm_mmu_flags */
	.long	0			/* proc_info_list.__cpu_io_mmu_flags */
	initfn	\initfunc, \name
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \hwcaps
	.long	cpu_v7m_name
	.long   \proc_fns
	.long	0			/* proc_info_list.tlb */
	.long	0			/* proc_info_list.user */
	.long	\cache_fns
.endm

	/*
	 * Match ARM Cortex-M55 processor.
	 */
	.type	__v7m_cm55_proc_info, #object
__v7m_cm55_proc_info:
	.long	0x410fd220		/* ARM Cortex-M55 0xD22 */
	.long	0xff0ffff0		/* Mask off revision, patch release */
	__v7m_proc __v7m_cm55_proc_info, __v7m_cm7_setup, hwcaps = HWCAP_EDSP, cache_fns = v7m_cache_fns, proc_fns = cm7_processor_functions
	.size	__v7m_cm55_proc_info, . - __v7m_cm55_proc_info

	/*
	 * Match ARM Cortex-M33 processor.
	 */
	.type	__v7m_cm33_proc_info, #object
__v7m_cm33_proc_info:
	.long	0x410fd210		/* ARM Cortex-M33 0xD21 */
	.long	0xff0ffff0		/* Mask off revision, patch release */
	__v7m_proc __v7m_cm33_proc_info, __v7m_setup, hwcaps = HWCAP_EDSP
	.size	__v7m_cm33_proc_info, . - __v7m_cm33_proc_info

	/*
	 * Match ARM Cortex-M7 processor.
	 */
	.type	__v7m_cm7_proc_info, #object
__v7m_cm7_proc_info:
	.long	0x410fc270		/* ARM Cortex-M7 0xC27 */
	.long	0xff0ffff0		/* Mask off revision, patch release */
	__v7m_proc __v7m_cm7_proc_info, __v7m_cm7_setup, hwcaps = HWCAP_EDSP, cache_fns = v7m_cache_fns, proc_fns = cm7_processor_functions
	.size	__v7m_cm7_proc_info, . - __v7m_cm7_proc_info

	/*
	 * Match ARM Cortex-M4 processor.
	 */
	.type	__v7m_cm4_proc_info, #object
__v7m_cm4_proc_info:
	.long	0x410fc240		/* ARM Cortex-M4 0xC24 */
	.long	0xff0ffff0		/* Mask off revision, patch release */
	__v7m_proc __v7m_cm4_proc_info, __v7m_setup, hwcaps = HWCAP_EDSP
	.size	__v7m_cm4_proc_info, . - __v7m_cm4_proc_info

	/*
	 * Match ARM Cortex-M3 processor.
	 */
	.type	__v7m_cm3_proc_info, #object
__v7m_cm3_proc_info:
	.long	0x410fc230		/* ARM Cortex-M3 0xC23 */
	.long	0xff0ffff0		/* Mask off revision, patch release */
	__v7m_proc __v7m_cm3_proc_info, __v7m_setup
	.size	__v7m_cm3_proc_info, . - __v7m_cm3_proc_info

	/*
	 * Match any ARMv7-M processor core.
	 */
	.type	__v7m_proc_info, #object
__v7m_proc_info:
	.long	0x000f0000		@ Required ID value
	.long	0x000f0000		@ Mask for ID
	__v7m_proc __v7m_proc_info, __v7m_setup
	.size	__v7m_proc_info, . - __v7m_proc_info


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * linux/arch/arm/mm/proc-xsc3.S
 *
 * Original Author: Matthew Gilbert
 * Current Maintainer: Lennert Buytenhek <buytenh@wantstofly.org>
 *
 * Copyright 2004 (C) Intel Corp.
 * Copyright 2005 (C) MontaVista Software, Inc.
 *
 * MMU functions for the Intel XScale3 Core (XSC3).  The XSC3 core is
 * an extension to Intel's original XScale core that adds the following
 * features:
 *
 * - ARMv6 Supersections
 * - Low Locality Reference pages (replaces mini-cache)
 * - 36-bit addressing
 * - L2 cache
 * - Cache coherency if chipset supports it
 *
 * Based on original XScale code by Nicolas Pitre.
 */

#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/pgtable.h>
#include <asm/assembler.h>
#include <asm/hwcap.h>
#include <asm/pgtable-hwdef.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include "proc-macros.S"

/*
 * This is the maximum size of an area which will be flushed.  If the
 * area is larger than this, then we flush the whole cache.
 */
#define MAX_AREA_SIZE	32768

/*
 * The cache line size of the L1 I, L1 D and unified L2 cache.
 */
#define CACHELINESIZE	32

/*
 * The size of the L1 D cache.
 */
#define CACHESIZE	32768

/*
 * This macro is used to wait for a CP15 write and is needed when we
 * have to ensure that the last operation to the coprocessor was
 * completed before continuing with operation.
 */
	.macro	cpwait_ret, lr, rd
	mrc	p15, 0, \rd, c2, c0, 0		@ arbitrary read of cp15
	sub	pc, \lr, \rd, LSR #32		@ wait for completion and
						@ flush instruction pipeline
	.endm

/*
 * This macro cleans and invalidates the entire L1 D cache.
 */

 	.macro  clean_d_cache rd, rs
	mov	\rd, #0x1f00
	orr	\rd, \rd, #0x00e0
1:	mcr	p15, 0, \rd, c7, c14, 2		@ clean/invalidate L1 D line
	adds	\rd, \rd, #0x40000000
	bcc	1b
	subs	\rd, \rd, #0x20
	bpl	1b
	.endm

	.text

/*
 * cpu_xsc3_proc_init()
 *
 * Nothing too exciting at the moment
 */
ENTRY(cpu_xsc3_proc_init)
	ret	lr

/*
 * cpu_xsc3_proc_fin()
 */
ENTRY(cpu_xsc3_proc_fin)
	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
	bic	r0, r0, #0x1800			@ ...IZ...........
	bic	r0, r0, #0x0006			@ .............CA.
	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
	ret	lr

/*
 * cpu_xsc3_reset(loc)
 *
 * Perform a soft reset of the system.  Put the CPU into the
 * same state as it would be if it had been reset, and branch
 * to what would be the reset vector.
 *
 * loc: location to jump to for soft reset
 */
	.align	5
	.pushsection	.idmap.text, "ax"
ENTRY(cpu_xsc3_reset)
	mov	r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
	msr	cpsr_c, r1			@ reset CPSR
	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
	bic	r1, r1, #0x3900			@ ..VIZ..S........
	bic	r1, r1, #0x0086			@ ........B....CA.
	mcr	p15, 0, r1, c1, c0, 0		@ ctrl register
	mcr	p15, 0, ip, c7, c7, 0		@ invalidate L1 caches and BTB
	bic	r1, r1, #0x0001			@ ...............M
	mcr	p15, 0, r1, c1, c0, 0		@ ctrl register
	@ CAUTION: MMU turned off from this point.  We count on the pipeline
	@ already containing those two last instructions to survive.
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I and D TLBs
	ret	r0
ENDPROC(cpu_xsc3_reset)
	.popsection

/*
 * cpu_xsc3_do_idle()
 *
 * Cause the processor to idle
 *
 * For now we do nothing but go to idle mode for every case
 *
 * XScale supports clock switching, but using idle mode support
 * allows external hardware to react to system state changes.
 */
	.align	5

ENTRY(cpu_xsc3_do_idle)
	mov	r0, #1
	mcr	p14, 0, r0, c7, c0, 0		@ go to idle
	ret	lr

/* ================================= CACHE ================================ */

/*
 *	flush_icache_all()
 *
 *	Unconditionally clean and invalidate the entire icache.
 */
ENTRY(xsc3_flush_icache_all)
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
	ret	lr
ENDPROC(xsc3_flush_icache_all)

/*
 *	flush_user_cache_all()
 *
 *	Invalidate all cache entries in a particular address
 *	space.
 */
ENTRY(xsc3_flush_user_cache_all)
	/* FALLTHROUGH */

/*
 *	flush_kern_cache_all()
 *
 *	Clean and invalidate the entire cache.
 */
ENTRY(xsc3_flush_kern_cache_all)
	mov	r2, #VM_EXEC
	mov	ip, #0
__flush_whole_cache:
	clean_d_cache r0, r1
	tst	r2, #VM_EXEC
	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate L1 I cache and BTB
	mcrne	p15, 0, ip, c7, c10, 4		@ data write barrier
	mcrne	p15, 0, ip, c7, c5, 4		@ prefetch flush
	ret	lr

/*
 *	flush_user_cache_range(start, end, vm_flags)
 *
 *	Invalidate a range of cache entries in the specified
 *	address space.
 *
 *	- start - start address (may not be aligned)
 *	- end	- end address (exclusive, may not be aligned)
 *	- vma	- vma_area_struct describing address space
 */
	.align	5
ENTRY(xsc3_flush_user_cache_range)
	mov	ip, #0
	sub	r3, r1, r0			@ calculate total size
	cmp	r3, #MAX_AREA_SIZE
	bhs	__flush_whole_cache

1:	tst	r2, #VM_EXEC
	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate L1 I line
	mcr	p15, 0, r0, c7, c14, 1		@ clean/invalidate L1 D line
	add	r0, r0, #CACHELINESIZE
	cmp	r0, r1
	blo	1b
	tst	r2, #VM_EXEC
	mcrne	p15, 0, ip, c7, c5, 6		@ invalidate BTB
	mcrne	p15, 0, ip, c7, c10, 4		@ data write barrier
	mcrne	p15, 0, ip, c7, c5, 4		@ prefetch flush
	ret	lr

/*
 *	coherent_kern_range(start, end)
 *
 *	Ensure coherency between the I cache and the D cache in the
 *	region described by start.  If you have non-snooping
 *	Harvard caches, you need to implement this function.
 *
 *	- start  - virtual start address
 *	- end	 - virtual end address
 *
 *	Note: single I-cache line invalidation isn't used here since
 *	it also trashes the mini I-cache used by JTAG debuggers.
 */
ENTRY(xsc3_coherent_kern_range)
/* FALLTHROUGH */
ENTRY(xsc3_coherent_user_range)
	bic	r0, r0, #CACHELINESIZE - 1
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean L1 D line
	add	r0, r0, #CACHELINESIZE
	cmp	r0, r1
	blo	1b
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate L1 I cache and BTB
	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
	mcr	p15, 0, r0, c7, c5, 4		@ prefetch flush
	ret	lr

/*
 *	flush_kern_dcache_area(void *addr, size_t size)
 *
 *	Ensure no D cache aliasing occurs, either with itself or
 *	the I cache.
 *
 *	- addr	- kernel address
 *	- size	- region size
 */
ENTRY(xsc3_flush_kern_dcache_area)
	add	r1, r0, r1
1:	mcr	p15, 0, r0, c7, c14, 1		@ clean/invalidate L1 D line
	add	r0, r0, #CACHELINESIZE
	cmp	r0, r1
	blo	1b
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0		@ invalidate L1 I cache and BTB
	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
	mcr	p15, 0, r0, c7, c5, 4		@ prefetch flush
	ret	lr

/*
 *	dma_inv_range(start, end)
 *
 *	Invalidate (discard) the specified virtual address range.
 *	May not write back any entries.  If 'start' or 'end'
 *	are not cache line aligned, those lines must be written
 *	back.
 *
 *	- start  - virtual start address
 *	- end	 - virtual end address
 */
xsc3_dma_inv_range:
	tst	r0, #CACHELINESIZE - 1
	bic	r0, r0, #CACHELINESIZE - 1
	mcrne	p15, 0, r0, c7, c10, 1		@ clean L1 D line
	tst	r1, #CACHELINESIZE - 1
	mcrne	p15, 0, r1, c7, c10, 1		@ clean L1 D line
1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate L1 D line
	add	r0, r0, #CACHELINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
	ret	lr

/*
 *	dma_clean_range(start, end)
 *
 *	Clean the specified virtual address range.
 *
 *	- start  - virtual start address
 *	- end	 - virtual end address
 */
xsc3_dma_clean_range:
	bic	r0, r0, #CACHELINESIZE - 1
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean L1 D line
	add	r0, r0, #CACHELINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
	ret	lr

/*
 *	dma_flush_range(start, end)
 *
 *	Clean and invalidate the specified virtual address range.
 *
 *	- start  - virtual start address
 *	- end	 - virtual end address
 */
ENTRY(xsc3_dma_flush_range)
	bic	r0, r0, #CACHELINESIZE - 1
1:	mcr	p15, 0, r0, c7, c14, 1		@ clean/invalidate L1 D line
	add	r0, r0, #CACHELINESIZE
	cmp	r0, r1
	blo	1b
	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
	ret	lr

/*
 *	dma_map_area(start, size, dir)
 *	- start	- kernel virtual start address
 *	- size	- size of region
 *	- dir	- DMA direction
 */
ENTRY(xsc3_dma_map_area)
	add	r1, r1, r0
	cmp	r2, #DMA_TO_DEVICE
	beq	xsc3_dma_clean_range
	bcs	xsc3_dma_inv_range
	b	xsc3_dma_flush_range
ENDPROC(xsc3_dma_map_area)

/*
 *	dma_unmap_area(start, size, dir)
 *	- start	- kernel virtual start address
 *	- size	- size of region
 *	- dir	- DMA direction
 */
ENTRY(xsc3_dma_unmap_area)
	ret	lr
ENDPROC(xsc3_dma_unmap_area)

	.globl	xsc3_flush_kern_cache_louis
	.equ	xsc3_flush_kern_cache_louis, xsc3_flush_kern_cache_all

	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
	define_cache_functions xsc3

ENTRY(cpu_xsc3_dcache_clean_area)
1:	mcr	p15, 0, r0, c7, c10, 1		@ clean L1 D line
	add	r0, r0, #CACHELINESIZE
	subs	r1, r1, #CACHELINESIZE
	bhi	1b
	ret	lr

/* =============================== PageTable ============================== */

/*
 * cpu_xsc3_switch_mm(pgd)
 *
 * Set the translation base pointer to be as described by pgd.
 *
 * pgd: new page tables
 */
	.align	5
ENTRY(cpu_xsc3_switch_mm)
	clean_d_cache r1, r2
	mcr	p15, 0, ip, c7, c5, 0		@ invalidate L1 I cache and BTB
	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
	mcr	p15, 0, ip, c7, c5, 4		@ prefetch flush
	orr	r0, r0, #0x18			@ cache the page table in L2
	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I and D TLBs
	cpwait_ret lr, ip

/*
 * cpu_xsc3_set_pte_ext(ptep, pte, ext)
 *
 * Set a PTE and flush it out
 */
cpu_xsc3_mt_table:
	.long	0x00						@ L_PTE_MT_UNCACHED
	.long	PTE_EXT_TEX(1)					@ L_PTE_MT_BUFFERABLE
	.long	PTE_EXT_TEX(5) | PTE_CACHEABLE			@ L_PTE_MT_WRITETHROUGH
	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_WRITEBACK
	.long	PTE_EXT_TEX(1) | PTE_BUFFERABLE			@ L_PTE_MT_DEV_SHARED
	.long	0x00						@ unused
	.long	0x00						@ L_PTE_MT_MINICACHE (not present)
	.long	PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE	@ L_PTE_MT_WRITEALLOC (not present?)
	.long	0x00						@ unused
	.long	PTE_EXT_TEX(1)					@ L_PTE_MT_DEV_WC
	.long	0x00						@ unused
	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_DEV_CACHED
	.long	PTE_EXT_TEX(2)					@ L_PTE_MT_DEV_NONSHARED
	.long	0x00						@ unused
	.long	0x00						@ unused
	.long	0x00						@ unused

	.align	5
ENTRY(cpu_xsc3_set_pte_ext)
	xscale_set_pte_ext_prologue

	tst	r1, #L_PTE_SHARED		@ shared?
	and	r1, r1, #L_PTE_MT_MASK
	adr	ip, cpu_xsc3_mt_table
	ldr	ip, [ip, r1]
	orrne	r2, r2, #PTE_EXT_COHERENT	@ interlock: mask in coherent bit
	bic	r2, r2, #0x0c			@ clear old C,B bits
	orr	r2, r2, ip

	xscale_set_pte_ext_epilogue
	ret	lr

	.ltorg
	.align

.globl	cpu_xsc3_suspend_size
.equ	cpu_xsc3_suspend_size, 4 * 6
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_xsc3_do_suspend)
	stmfd	sp!, {r4 - r9, lr}
	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
	mrc	p15, 0, r6, c13, c0, 0	@ PID
	mrc 	p15, 0, r7, c3, c0, 0	@ domain ID
	mrc	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
	mrc 	p15, 0, r9, c1, c0, 0	@ control reg
	bic	r4, r4, #2		@ clear frequency change bit
	stmia	r0, {r4 - r9}		@ store cp regs
	ldmia	sp!, {r4 - r9, pc}
ENDPROC(cpu_xsc3_do_suspend)

ENTRY(cpu_xsc3_do_resume)
	ldmia	r0, {r4 - r9}		@ load cp regs
	mov	ip, #0
	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
	mcr	p15, 0, ip, c7, c10, 4	@ drain write (&fill) buffer
	mcr	p15, 0, ip, c7, c5, 4	@ flush prefetch buffer
	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
	mcr	p15, 0, r6, c13, c0, 0	@ PID
	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
	orr	r1, r1, #0x18		@ cache the page table in L2
	mcr	p15, 0, r1, c2, c0, 0	@ translation table base addr
	mcr	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
	mov	r0, r9			@ control register
	b	cpu_resume_mmu
ENDPROC(cpu_xsc3_do_resume)
#endif

	.type	__xsc3_setup, #function
__xsc3_setup:
	mov	r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
	msr	cpsr_c, r0
	mcr	p15, 0, ip, c7, c7, 0		@ invalidate L1 caches and BTB
	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
	mcr	p15, 0, ip, c7, c5, 4		@ prefetch flush
	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I and D TLBs
	orr	r4, r4, #0x18			@ cache the page table in L2
	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer

	mov	r0, #1 << 6			@ cp6 access for early sched_clock
	mcr	p15, 0, r0, c15, c1, 0		@ write CP access register

	mrc	p15, 0, r0, c1, c0, 1		@ get auxiliary control reg
	and	r0, r0, #2			@ preserve bit P bit setting
	orr	r0, r0, #(1 << 10)		@ enable L2 for LLR cache
	mcr	p15, 0, r0, c1, c0, 1		@ set auxiliary control reg

	adr	r5, xsc3_crval
	ldmia	r5, {r5, r6}

#ifdef CONFIG_CACHE_XSC3L2
	mrc	p15, 1, r0, c0, c0, 1		@ get L2 present information
	ands	r0, r0, #0xf8
	orrne	r6, r6, #(1 << 26)		@ enable L2 if present
#endif

	mrc	p15, 0, r0, c1, c0, 0		@ get control register
	bic	r0, r0, r5			@ ..V. ..R. .... ..A.
	orr	r0, r0, r6			@ ..VI Z..S .... .C.M (mmu)
						@ ...I Z..S .... .... (uc)
	ret	lr

	.size	__xsc3_setup, . - __xsc3_setup

	.type	xsc3_crval, #object
xsc3_crval:
	crval	clear=0x04002202, mmuset=0x00003905, ucset=0x00001900

	__INITDATA

	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
	define_processor_functions xsc3, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1

	.section ".rodata"

	string	cpu_arch_name, "armv5te"
	string	cpu_elf_name, "v5"
	string	cpu_xsc3_name, "XScale-V3 based processor"

	.align

	.section ".proc.info.init", "a"

.macro xsc3_proc_info name:req, cpu_val:req, cpu_mask:req
	.type	__\name\()_proc_info,#object
__\name\()_proc_info:
	.long	\cpu_val
	.long	\cpu_mask
	.long	PMD_TYPE_SECT | \
		PMD_SECT_BUFFERABLE | \
		PMD_SECT_CACHEABLE | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	.long	PMD_TYPE_SECT | \
		PMD_SECT_AP_WRITE | \
		PMD_SECT_AP_READ
	initfn	__xsc3_setup, __\name\()_proc_info
	.long	cpu_arch_name
	.long	cpu_elf_name
	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
	.long	cpu_xsc3_name
	.long	xsc3_processor_functions
	.long	v4wbi_tlb_fns
	.long	xsc3_mc_user_fns
	.long	xsc3_cache_fns
	.size	__\name\()_proc_info, . - __\name\()_proc_info
.endm

	xsc3_proc_info xsc3, 0x69056000, 0xffffe000

/* Note: PXA935 changed its implementor ID from Intel to Marvell */
	xsc3_proc_info xsc3_pxa935, 0x56056000, 0xffffe000