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