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: |
2e8a5942 GC |
49 | mov pc, lr |
50 | ENDPROC(ll_get_coherency_base) | |
51 | ||
4dd1b7fa | 52 | /* Returns the CPU ID in r3 (r0 is untouched) */ |
2e8a5942 GC |
53 | ENTRY(ll_get_cpuid) |
54 | mrc 15, 0, r3, cr0, cr0, 5 | |
55 | and r3, r3, #15 | |
b41375f7 | 56 | mov r2, #(1 << 24) |
2e8a5942 | 57 | lsl r3, r2, r3 |
4fbe6393 | 58 | ARM_BE8(rev r3, r3) |
2e8a5942 GC |
59 | mov pc, lr |
60 | ENDPROC(ll_get_cpuid) | |
009f1315 | 61 | |
4dd1b7fa TP |
62 | /* |
63 | * ll_add_cpu_to_smp_group(), ll_enable_coherency() and | |
64 | * ll_disable_coherency() use the strex/ldrex instructions while the | |
65 | * MMU can be disabled. The Armada XP SoC has an exclusive monitor | |
66 | * that tracks transactions to Device and/or SO memory and thanks to | |
67 | * that, exclusive transactions are functional even when the MMU is | |
68 | * disabled. | |
2e8a5942 | 69 | */ |
009f1315 | 70 | |
2e8a5942 GC |
71 | ENTRY(ll_add_cpu_to_smp_group) |
72 | /* | |
4dd1b7fa TP |
73 | * As r0 is not modified by ll_get_coherency_base() and |
74 | * ll_get_cpuid(), we use it to temporarly save lr and avoid | |
75 | * it being modified by the branch and link calls. This | |
76 | * function is used very early in the secondary CPU boot, and | |
77 | * no stack is available at this point. | |
2e8a5942 | 78 | */ |
90ba76f6 | 79 | mov r0, lr |
2e8a5942 GC |
80 | bl ll_get_coherency_base |
81 | bl ll_get_cpuid | |
90ba76f6 | 82 | mov lr, r0 |
2e8a5942 | 83 | add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET |
b60b61d4 | 84 | 1: |
2e8a5942 GC |
85 | ldrex r2, [r0] |
86 | orr r2, r2, r3 | |
87 | strex r1, r2, [r0] | |
88 | cmp r1, #0 | |
89 | bne 1b | |
90 | mov pc, lr | |
91 | ENDPROC(ll_add_cpu_to_smp_group) | |
009f1315 | 92 | |
2e8a5942 GC |
93 | ENTRY(ll_enable_coherency) |
94 | /* | |
4dd1b7fa TP |
95 | * As r0 is not modified by ll_get_coherency_base() and |
96 | * ll_get_cpuid(), we use it to temporarly save lr and avoid | |
97 | * it being modified by the branch and link calls. This | |
98 | * function is used very early in the secondary CPU boot, and | |
99 | * no stack is available at this point. | |
2e8a5942 GC |
100 | */ |
101 | mov r0, lr | |
102 | bl ll_get_coherency_base | |
103 | bl ll_get_cpuid | |
104 | mov lr, r0 | |
105 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET | |
106 | 1: | |
107 | ldrex r2, [r0] | |
108 | orr r2, r2, r3 | |
109 | strex r1, r2, [r0] | |
110 | cmp r1, #0 | |
111 | bne 1b | |
009f1315 | 112 | dsb |
009f1315 GC |
113 | mov r0, #0 |
114 | mov pc, lr | |
2e8a5942 GC |
115 | ENDPROC(ll_enable_coherency) |
116 | ||
1a6bfbc3 GC |
117 | ENTRY(ll_disable_coherency) |
118 | /* | |
4dd1b7fa TP |
119 | * As r0 is not modified by ll_get_coherency_base() and |
120 | * ll_get_cpuid(), we use it to temporarly save lr and avoid | |
121 | * it being modified by the branch and link calls. This | |
122 | * function is used very early in the secondary CPU boot, and | |
123 | * no stack is available at this point. | |
1a6bfbc3 | 124 | */ |
90ba76f6 | 125 | mov r0, lr |
1a6bfbc3 GC |
126 | bl ll_get_coherency_base |
127 | bl ll_get_cpuid | |
90ba76f6 | 128 | mov lr, r0 |
1a6bfbc3 GC |
129 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET |
130 | 1: | |
131 | ldrex r2, [r0] | |
132 | bic r2, r2, r3 | |
133 | strex r1, r2, [r0] | |
134 | cmp r1, #0 | |
135 | bne 1b | |
136 | dsb | |
137 | mov pc, lr | |
138 | ENDPROC(ll_disable_coherency) | |
ccd6a131 GC |
139 | |
140 | .align 2 | |
141 | 3: | |
142 | .long coherency_phys_base - . |