Commit | Line | Data |
---|---|---|
009f1315 GC |
1 | /* |
2 | * Coherency fabric: low level functions | |
3 | * | |
4 | * Copyright (C) 2012 Marvell | |
5 | * | |
6 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | |
7 | * | |
8 | * This file is licensed under the terms of the GNU General Public | |
9 | * License version 2. This program is licensed "as is" without any | |
10 | * warranty of any kind, whether express or implied. | |
11 | * | |
12 | * This file implements the assembly function to add a CPU to the | |
13 | * coherency fabric. This function is called by each of the secondary | |
14 | * CPUs during their early boot in an SMP kernel, this why this | |
15 | * function have to callable from assembly. It can also be called by a | |
16 | * primary CPU from C code during its boot. | |
17 | */ | |
18 | ||
19 | #include <linux/linkage.h> | |
20 | #define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0 | |
21 | #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 | |
22 | ||
bca028e7 | 23 | #include <asm/assembler.h> |
ccd6a131 | 24 | #include <asm/cp15.h> |
bca028e7 | 25 | |
009f1315 | 26 | .text |
4dd1b7fa | 27 | /* Returns the coherency base address in r1 (r0 is untouched) */ |
2e8a5942 | 28 | ENTRY(ll_get_coherency_base) |
ccd6a131 GC |
29 | mrc p15, 0, r1, c1, c0, 0 |
30 | tst r1, #CR_M @ Check MMU bit enabled | |
31 | bne 1f | |
32 | ||
4dd1b7fa TP |
33 | /* |
34 | * MMU is disabled, use the physical address of the coherency | |
35 | * base address. | |
36 | */ | |
2e8a5942 GC |
37 | adr r1, 3f |
38 | ldr r3, [r1] | |
39 | ldr r1, [r1, r3] | |
ccd6a131 GC |
40 | b 2f |
41 | 1: | |
4dd1b7fa TP |
42 | /* |
43 | * MMU is enabled, use the virtual address of the coherency | |
44 | * base address. | |
45 | */ | |
2e8a5942 GC |
46 | ldr r1, =coherency_base |
47 | ldr r1, [r1] | |
ccd6a131 | 48 | 2: |
6ebbf2ce | 49 | ret lr |
2e8a5942 GC |
50 | ENDPROC(ll_get_coherency_base) |
51 | ||
07ae144b TP |
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) | |
2e8a5942 GC |
61 | mrc 15, 0, r3, cr0, cr0, 5 |
62 | and r3, r3, #15 | |
b41375f7 | 63 | mov r2, #(1 << 24) |
2e8a5942 | 64 | lsl r3, r2, r3 |
4fbe6393 | 65 | ARM_BE8(rev r3, r3) |
6ebbf2ce | 66 | ret lr |
07ae144b | 67 | ENDPROC(ll_get_coherency_cpumask) |
009f1315 | 68 | |
4dd1b7fa TP |
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. | |
2e8a5942 | 76 | */ |
009f1315 | 77 | |
2e8a5942 GC |
78 | ENTRY(ll_add_cpu_to_smp_group) |
79 | /* | |
4dd1b7fa | 80 | * As r0 is not modified by ll_get_coherency_base() and |
07ae144b TP |
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. | |
2e8a5942 | 85 | */ |
90ba76f6 | 86 | mov r0, lr |
2e8a5942 | 87 | bl ll_get_coherency_base |
07ae144b | 88 | bl ll_get_coherency_cpumask |
90ba76f6 | 89 | mov lr, r0 |
2e8a5942 | 90 | add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET |
b60b61d4 | 91 | 1: |
2e8a5942 GC |
92 | ldrex r2, [r0] |
93 | orr r2, r2, r3 | |
94 | strex r1, r2, [r0] | |
95 | cmp r1, #0 | |
96 | bne 1b | |
6ebbf2ce | 97 | ret lr |
2e8a5942 | 98 | ENDPROC(ll_add_cpu_to_smp_group) |
009f1315 | 99 | |
2e8a5942 GC |
100 | ENTRY(ll_enable_coherency) |
101 | /* | |
4dd1b7fa | 102 | * As r0 is not modified by ll_get_coherency_base() and |
07ae144b TP |
103 | * ll_get_coherency_cpumask(), we use it to temporarly save lr |
104 | * and avoid it being modified by the branch and link | |
105 | * calls. This function is used very early in the secondary | |
106 | * CPU boot, and no stack is available at this point. | |
2e8a5942 GC |
107 | */ |
108 | mov r0, lr | |
109 | bl ll_get_coherency_base | |
07ae144b | 110 | bl ll_get_coherency_cpumask |
2e8a5942 GC |
111 | mov lr, r0 |
112 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET | |
113 | 1: | |
114 | ldrex r2, [r0] | |
115 | orr r2, r2, r3 | |
116 | strex r1, r2, [r0] | |
117 | cmp r1, #0 | |
118 | bne 1b | |
009f1315 | 119 | dsb |
009f1315 | 120 | mov r0, #0 |
6ebbf2ce | 121 | ret lr |
2e8a5942 GC |
122 | ENDPROC(ll_enable_coherency) |
123 | ||
1a6bfbc3 GC |
124 | ENTRY(ll_disable_coherency) |
125 | /* | |
4dd1b7fa | 126 | * As r0 is not modified by ll_get_coherency_base() and |
07ae144b TP |
127 | * ll_get_coherency_cpumask(), we use it to temporarly save lr |
128 | * and avoid it being modified by the branch and link | |
129 | * calls. This function is used very early in the secondary | |
130 | * CPU boot, and no stack is available at this point. | |
1a6bfbc3 | 131 | */ |
90ba76f6 | 132 | mov r0, lr |
1a6bfbc3 | 133 | bl ll_get_coherency_base |
07ae144b | 134 | bl ll_get_coherency_cpumask |
90ba76f6 | 135 | mov lr, r0 |
1a6bfbc3 GC |
136 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET |
137 | 1: | |
138 | ldrex r2, [r0] | |
139 | bic r2, r2, r3 | |
140 | strex r1, r2, [r0] | |
141 | cmp r1, #0 | |
142 | bne 1b | |
143 | dsb | |
6ebbf2ce | 144 | ret lr |
1a6bfbc3 | 145 | ENDPROC(ll_disable_coherency) |
ccd6a131 GC |
146 | |
147 | .align 2 | |
148 | 3: | |
149 | .long coherency_phys_base - . |