xref: /OK3568_Linux_fs/kernel/arch/arm/mach-mvebu/coherency_ll.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun * Coherency fabric: low level functions
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2012 Marvell
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Gregory CLEMENT <gregory.clement@free-electrons.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This file is licensed under the terms of the GNU General Public
9*4882a593Smuzhiyun * License version 2.  This program is licensed "as is" without any
10*4882a593Smuzhiyun * warranty of any kind, whether express or implied.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * This file implements the assembly function to add a CPU to the
13*4882a593Smuzhiyun * coherency fabric. This function is called by each of the secondary
14*4882a593Smuzhiyun * CPUs during their early boot in an SMP kernel, this why this
15*4882a593Smuzhiyun * function have to callable from assembly. It can also be called by a
16*4882a593Smuzhiyun * primary CPU from C code during its boot.
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun#include <linux/linkage.h>
20*4882a593Smuzhiyun#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0
21*4882a593Smuzhiyun#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun#include <asm/assembler.h>
24*4882a593Smuzhiyun#include <asm/cp15.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun	.text
27*4882a593Smuzhiyun/*
28*4882a593Smuzhiyun * Returns the coherency base address in r1 (r0 is untouched), or 0 if
29*4882a593Smuzhiyun * the coherency fabric is not enabled.
30*4882a593Smuzhiyun */
31*4882a593SmuzhiyunENTRY(ll_get_coherency_base)
32*4882a593Smuzhiyun	mrc	p15, 0, r1, c1, c0, 0
33*4882a593Smuzhiyun	tst	r1, #CR_M @ Check MMU bit enabled
34*4882a593Smuzhiyun	bne	1f
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun	/*
37*4882a593Smuzhiyun	 * MMU is disabled, use the physical address of the coherency
38*4882a593Smuzhiyun	 * base address, (or 0x0 if the coherency fabric is not mapped)
39*4882a593Smuzhiyun	 */
40*4882a593Smuzhiyun	adr	r1, 3f
41*4882a593Smuzhiyun	ldr	r3, [r1]
42*4882a593Smuzhiyun	ldr	r1, [r1, r3]
43*4882a593Smuzhiyun	b	2f
44*4882a593Smuzhiyun1:
45*4882a593Smuzhiyun	/*
46*4882a593Smuzhiyun	 * MMU is enabled, use the virtual address of the coherency
47*4882a593Smuzhiyun	 * base address.
48*4882a593Smuzhiyun	 */
49*4882a593Smuzhiyun	ldr	r1, =coherency_base
50*4882a593Smuzhiyun	ldr	r1, [r1]
51*4882a593Smuzhiyun2:
52*4882a593Smuzhiyun	ret	lr
53*4882a593SmuzhiyunENDPROC(ll_get_coherency_base)
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun/*
56*4882a593Smuzhiyun * Returns the coherency CPU mask in r3 (r0 is untouched). This
57*4882a593Smuzhiyun * coherency CPU mask can be used with the coherency fabric
58*4882a593Smuzhiyun * configuration and control registers. Note that the mask is already
59*4882a593Smuzhiyun * endian-swapped as appropriate so that the calling functions do not
60*4882a593Smuzhiyun * have to care about endianness issues while accessing the coherency
61*4882a593Smuzhiyun * fabric registers
62*4882a593Smuzhiyun */
63*4882a593SmuzhiyunENTRY(ll_get_coherency_cpumask)
64*4882a593Smuzhiyun	mrc	p15, 0, r3, cr0, cr0, 5
65*4882a593Smuzhiyun	and	r3, r3, #15
66*4882a593Smuzhiyun	mov	r2, #(1 << 24)
67*4882a593Smuzhiyun	lsl	r3, r2, r3
68*4882a593SmuzhiyunARM_BE8(rev	r3, r3)
69*4882a593Smuzhiyun	ret	lr
70*4882a593SmuzhiyunENDPROC(ll_get_coherency_cpumask)
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun/*
73*4882a593Smuzhiyun * ll_add_cpu_to_smp_group(), ll_enable_coherency() and
74*4882a593Smuzhiyun * ll_disable_coherency() use the strex/ldrex instructions while the
75*4882a593Smuzhiyun * MMU can be disabled. The Armada XP SoC has an exclusive monitor
76*4882a593Smuzhiyun * that tracks transactions to Device and/or SO memory and thanks to
77*4882a593Smuzhiyun * that, exclusive transactions are functional even when the MMU is
78*4882a593Smuzhiyun * disabled.
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun
81*4882a593SmuzhiyunENTRY(ll_add_cpu_to_smp_group)
82*4882a593Smuzhiyun	/*
83*4882a593Smuzhiyun	 * As r0 is not modified by ll_get_coherency_base() and
84*4882a593Smuzhiyun	 * ll_get_coherency_cpumask(), we use it to temporarly save lr
85*4882a593Smuzhiyun	 * and avoid it being modified by the branch and link
86*4882a593Smuzhiyun	 * calls. This function is used very early in the secondary
87*4882a593Smuzhiyun	 * CPU boot, and no stack is available at this point.
88*4882a593Smuzhiyun	 */
89*4882a593Smuzhiyun	mov 	r0, lr
90*4882a593Smuzhiyun	bl	ll_get_coherency_base
91*4882a593Smuzhiyun	/* Bail out if the coherency is not enabled */
92*4882a593Smuzhiyun	cmp	r1, #0
93*4882a593Smuzhiyun	reteq	r0
94*4882a593Smuzhiyun	bl	ll_get_coherency_cpumask
95*4882a593Smuzhiyun	mov 	lr, r0
96*4882a593Smuzhiyun	add	r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
97*4882a593Smuzhiyun1:
98*4882a593Smuzhiyun	ldrex	r2, [r0]
99*4882a593Smuzhiyun	orr	r2, r2, r3
100*4882a593Smuzhiyun	strex	r1, r2, [r0]
101*4882a593Smuzhiyun	cmp	r1, #0
102*4882a593Smuzhiyun	bne	1b
103*4882a593Smuzhiyun	ret	lr
104*4882a593SmuzhiyunENDPROC(ll_add_cpu_to_smp_group)
105*4882a593Smuzhiyun
106*4882a593SmuzhiyunENTRY(ll_enable_coherency)
107*4882a593Smuzhiyun	/*
108*4882a593Smuzhiyun	 * As r0 is not modified by ll_get_coherency_base() and
109*4882a593Smuzhiyun	 * ll_get_coherency_cpumask(), we use it to temporarly save lr
110*4882a593Smuzhiyun	 * and avoid it being modified by the branch and link
111*4882a593Smuzhiyun	 * calls. This function is used very early in the secondary
112*4882a593Smuzhiyun	 * CPU boot, and no stack is available at this point.
113*4882a593Smuzhiyun	 */
114*4882a593Smuzhiyun	mov r0, lr
115*4882a593Smuzhiyun	bl	ll_get_coherency_base
116*4882a593Smuzhiyun	/* Bail out if the coherency is not enabled */
117*4882a593Smuzhiyun	cmp	r1, #0
118*4882a593Smuzhiyun	reteq	r0
119*4882a593Smuzhiyun	bl	ll_get_coherency_cpumask
120*4882a593Smuzhiyun	mov lr, r0
121*4882a593Smuzhiyun	add	r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
122*4882a593Smuzhiyun1:
123*4882a593Smuzhiyun	ldrex	r2, [r0]
124*4882a593Smuzhiyun	orr	r2, r2, r3
125*4882a593Smuzhiyun	strex	r1, r2, [r0]
126*4882a593Smuzhiyun	cmp	r1, #0
127*4882a593Smuzhiyun	bne	1b
128*4882a593Smuzhiyun	dsb
129*4882a593Smuzhiyun	mov	r0, #0
130*4882a593Smuzhiyun	ret	lr
131*4882a593SmuzhiyunENDPROC(ll_enable_coherency)
132*4882a593Smuzhiyun
133*4882a593SmuzhiyunENTRY(ll_disable_coherency)
134*4882a593Smuzhiyun	/*
135*4882a593Smuzhiyun	 * As r0 is not modified by ll_get_coherency_base() and
136*4882a593Smuzhiyun	 * ll_get_coherency_cpumask(), we use it to temporarly save lr
137*4882a593Smuzhiyun	 * and avoid it being modified by the branch and link
138*4882a593Smuzhiyun	 * calls. This function is used very early in the secondary
139*4882a593Smuzhiyun	 * CPU boot, and no stack is available at this point.
140*4882a593Smuzhiyun	 */
141*4882a593Smuzhiyun	mov 	r0, lr
142*4882a593Smuzhiyun	bl	ll_get_coherency_base
143*4882a593Smuzhiyun	/* Bail out if the coherency is not enabled */
144*4882a593Smuzhiyun	cmp	r1, #0
145*4882a593Smuzhiyun	reteq	r0
146*4882a593Smuzhiyun	bl	ll_get_coherency_cpumask
147*4882a593Smuzhiyun	mov 	lr, r0
148*4882a593Smuzhiyun	add	r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
149*4882a593Smuzhiyun1:
150*4882a593Smuzhiyun	ldrex	r2, [r0]
151*4882a593Smuzhiyun	bic	r2, r2, r3
152*4882a593Smuzhiyun	strex	r1, r2, [r0]
153*4882a593Smuzhiyun	cmp	r1, #0
154*4882a593Smuzhiyun	bne	1b
155*4882a593Smuzhiyun	dsb
156*4882a593Smuzhiyun	ret	lr
157*4882a593SmuzhiyunENDPROC(ll_disable_coherency)
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun	.align 2
160*4882a593Smuzhiyun3:
161*4882a593Smuzhiyun	.long	coherency_phys_base - .
162