167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * Coherency fabric: low level functions
 | 
						|
 *
 | 
						|
 * Copyright (C) 2012 Marvell
 | 
						|
 *
 | 
						|
 * Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
						|
 *
 | 
						|
 * This file is licensed under the terms of the GNU General Public
 | 
						|
 * License version 2.  This program is licensed "as is" without any
 | 
						|
 * warranty of any kind, whether express or implied.
 | 
						|
 *
 | 
						|
 * This file implements the assembly function to add a CPU to the
 | 
						|
 * coherency fabric. This function is called by each of the secondary
 | 
						|
 * CPUs during their early boot in an SMP kernel, this why this
 | 
						|
 * function have to callable from assembly. It can also be called by a
 | 
						|
 * primary CPU from C code during its boot.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/linkage.h>
 | 
						|
#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0
 | 
						|
#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
 | 
						|
 | 
						|
#include <asm/assembler.h>
 | 
						|
#include <asm/cp15.h>
 | 
						|
 | 
						|
	.text
 | 
						|
/*
 | 
						|
 * Returns the coherency base address in r1 (r0 is untouched), or 0 if
 | 
						|
 * the coherency fabric is not enabled.
 | 
						|
 */
 | 
						|
ENTRY(ll_get_coherency_base)
 | 
						|
	mrc	p15, 0, r1, c1, c0, 0
 | 
						|
	tst	r1, #CR_M @ Check MMU bit enabled
 | 
						|
	bne	1f
 | 
						|
 | 
						|
	/*
 | 
						|
	 * MMU is disabled, use the physical address of the coherency
 | 
						|
	 * base address. However, if the coherency fabric isn't mapped
 | 
						|
	 * (i.e its virtual address is zero), it means coherency is
 | 
						|
	 * not enabled, so we return 0.
 | 
						|
	 */
 | 
						|
	ldr	r1, =coherency_base
 | 
						|
	cmp	r1, #0
 | 
						|
	beq	2f
 | 
						|
	adr	r1, 3f
 | 
						|
	ldr	r3, [r1]
 | 
						|
	ldr	r1, [r1, r3]
 | 
						|
	b	2f
 | 
						|
1:
 | 
						|
	/*
 | 
						|
	 * MMU is enabled, use the virtual address of the coherency
 | 
						|
	 * base address.
 | 
						|
	 */
 | 
						|
	ldr	r1, =coherency_base
 | 
						|
	ldr	r1, [r1]
 | 
						|
2:
 | 
						|
	ret	lr
 | 
						|
ENDPROC(ll_get_coherency_base)
 | 
						|
 | 
						|
/*
 | 
						|
 * Returns the coherency CPU mask in r3 (r0 is untouched). This
 | 
						|
 * coherency CPU mask can be used with the coherency fabric
 | 
						|
 * configuration and control registers. Note that the mask is already
 | 
						|
 * endian-swapped as appropriate so that the calling functions do not
 | 
						|
 * have to care about endianness issues while accessing the coherency
 | 
						|
 * fabric registers
 | 
						|
 */
 | 
						|
ENTRY(ll_get_coherency_cpumask)
 | 
						|
	mrc	15, 0, r3, cr0, cr0, 5
 | 
						|
	and	r3, r3, #15
 | 
						|
	mov	r2, #(1 << 24)
 | 
						|
	lsl	r3, r2, r3
 | 
						|
ARM_BE8(rev	r3, r3)
 | 
						|
	ret	lr
 | 
						|
ENDPROC(ll_get_coherency_cpumask)
 | 
						|
 | 
						|
/*
 | 
						|
 * ll_add_cpu_to_smp_group(), ll_enable_coherency() and
 | 
						|
 * ll_disable_coherency() use the strex/ldrex instructions while the
 | 
						|
 * MMU can be disabled. The Armada XP SoC has an exclusive monitor
 | 
						|
 * that tracks transactions to Device and/or SO memory and thanks to
 | 
						|
 * that, exclusive transactions are functional even when the MMU is
 | 
						|
 * disabled.
 | 
						|
 */
 | 
						|
 | 
						|
ENTRY(ll_add_cpu_to_smp_group)
 | 
						|
	/*
 | 
						|
	 * As r0 is not modified by ll_get_coherency_base() and
 | 
						|
	 * ll_get_coherency_cpumask(), we use it to temporarly save lr
 | 
						|
	 * and avoid it being modified by the branch and link
 | 
						|
	 * calls. This function is used very early in the secondary
 | 
						|
	 * CPU boot, and no stack is available at this point.
 | 
						|
	 */
 | 
						|
	mov 	r0, lr
 | 
						|
	bl	ll_get_coherency_base
 | 
						|
	/* Bail out if the coherency is not enabled */
 | 
						|
	cmp	r1, #0
 | 
						|
	reteq	r0
 | 
						|
	bl	ll_get_coherency_cpumask
 | 
						|
	mov 	lr, r0
 | 
						|
	add	r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
 | 
						|
1:
 | 
						|
	ldrex	r2, [r0]
 | 
						|
	orr	r2, r2, r3
 | 
						|
	strex	r1, r2, [r0]
 | 
						|
	cmp	r1, #0
 | 
						|
	bne	1b
 | 
						|
	ret	lr
 | 
						|
ENDPROC(ll_add_cpu_to_smp_group)
 | 
						|
 | 
						|
ENTRY(ll_enable_coherency)
 | 
						|
	/*
 | 
						|
	 * As r0 is not modified by ll_get_coherency_base() and
 | 
						|
	 * ll_get_coherency_cpumask(), we use it to temporarly save lr
 | 
						|
	 * and avoid it being modified by the branch and link
 | 
						|
	 * calls. This function is used very early in the secondary
 | 
						|
	 * CPU boot, and no stack is available at this point.
 | 
						|
	 */
 | 
						|
	mov r0, lr
 | 
						|
	bl	ll_get_coherency_base
 | 
						|
	/* Bail out if the coherency is not enabled */
 | 
						|
	cmp	r1, #0
 | 
						|
	reteq	r0
 | 
						|
	bl	ll_get_coherency_cpumask
 | 
						|
	mov lr, r0
 | 
						|
	add	r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
 | 
						|
1:
 | 
						|
	ldrex	r2, [r0]
 | 
						|
	orr	r2, r2, r3
 | 
						|
	strex	r1, r2, [r0]
 | 
						|
	cmp	r1, #0
 | 
						|
	bne	1b
 | 
						|
	dsb
 | 
						|
	mov	r0, #0
 | 
						|
	ret	lr
 | 
						|
ENDPROC(ll_enable_coherency)
 | 
						|
 | 
						|
ENTRY(ll_disable_coherency)
 | 
						|
	/*
 | 
						|
	 * As r0 is not modified by ll_get_coherency_base() and
 | 
						|
	 * ll_get_coherency_cpumask(), we use it to temporarly save lr
 | 
						|
	 * and avoid it being modified by the branch and link
 | 
						|
	 * calls. This function is used very early in the secondary
 | 
						|
	 * CPU boot, and no stack is available at this point.
 | 
						|
	 */
 | 
						|
	mov 	r0, lr
 | 
						|
	bl	ll_get_coherency_base
 | 
						|
	/* Bail out if the coherency is not enabled */
 | 
						|
	cmp	r1, #0
 | 
						|
	reteq	r0
 | 
						|
	bl	ll_get_coherency_cpumask
 | 
						|
	mov 	lr, r0
 | 
						|
	add	r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
 | 
						|
1:
 | 
						|
	ldrex	r2, [r0]
 | 
						|
	bic	r2, r2, r3
 | 
						|
	strex	r1, r2, [r0]
 | 
						|
	cmp	r1, #0
 | 
						|
	bne	1b
 | 
						|
	dsb
 | 
						|
	ret	lr
 | 
						|
ENDPROC(ll_disable_coherency)
 | 
						|
 | 
						|
	.align 2
 | 
						|
3:
 | 
						|
	.long	coherency_phys_base - .
 |