diff options
Diffstat (limited to 'arch/arm/mach-mvebu/coherency_ll.S')
-rw-r--r-- | arch/arm/mach-mvebu/coherency_ll.S | 143 |
1 files changed, 117 insertions, 26 deletions
diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S index ee7598fe75db..510c29e079ca 100644 --- a/arch/arm/mach-mvebu/coherency_ll.S +++ b/arch/arm/mach-mvebu/coherency_ll.S | |||
@@ -21,38 +21,129 @@ | |||
21 | #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 | 21 | #define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 |
22 | 22 | ||
23 | #include <asm/assembler.h> | 23 | #include <asm/assembler.h> |
24 | #include <asm/cp15.h> | ||
24 | 25 | ||
25 | .text | 26 | .text |
27 | /* Returns the coherency base address in r1 (r0 is untouched) */ | ||
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. | ||
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 | mov pc, lr | ||
50 | ENDPROC(ll_get_coherency_base) | ||
51 | |||
26 | /* | 52 | /* |
27 | * r0: Coherency fabric base register address | 53 | * Returns the coherency CPU mask in r3 (r0 is untouched). This |
28 | * r1: HW CPU id | 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 | ||
29 | */ | 59 | */ |
30 | ENTRY(ll_set_cpu_coherent) | 60 | ENTRY(ll_get_coherency_cpumask) |
31 | /* Create bit by cpu index */ | 61 | mrc 15, 0, r3, cr0, cr0, 5 |
32 | mov r3, #(1 << 24) | 62 | and r3, r3, #15 |
33 | lsl r1, r3, r1 | 63 | mov r2, #(1 << 24) |
34 | ARM_BE8(rev r1, r1) | 64 | lsl r3, r2, r3 |
35 | 65 | ARM_BE8(rev r3, r3) | |
36 | /* Add CPU to SMP group - Atomic */ | 66 | mov pc, lr |
37 | add r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET | 67 | ENDPROC(ll_get_coherency_cpumask) |
38 | 1: | 68 | |
39 | ldrex r2, [r3] | 69 | /* |
40 | orr r2, r2, r1 | 70 | * ll_add_cpu_to_smp_group(), ll_enable_coherency() and |
41 | strex r0, r2, [r3] | 71 | * ll_disable_coherency() use the strex/ldrex instructions while the |
42 | cmp r0, #0 | 72 | * MMU can be disabled. The Armada XP SoC has an exclusive monitor |
43 | bne 1b | 73 | * that tracks transactions to Device and/or SO memory and thanks to |
44 | 74 | * that, exclusive transactions are functional even when the MMU is | |
45 | /* Enable coherency on CPU - Atomic */ | 75 | * disabled. |
46 | add r3, r3, #ARMADA_XP_CFB_CFG_REG_OFFSET | 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 | bl ll_get_coherency_cpumask | ||
89 | mov lr, r0 | ||
90 | add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET | ||
47 | 1: | 91 | 1: |
48 | ldrex r2, [r3] | 92 | ldrex r2, [r0] |
49 | orr r2, r2, r1 | 93 | orr r2, r2, r3 |
50 | strex r0, r2, [r3] | 94 | strex r1, r2, [r0] |
51 | cmp r0, #0 | 95 | cmp r1, #0 |
52 | bne 1b | 96 | bne 1b |
97 | mov pc, lr | ||
98 | ENDPROC(ll_add_cpu_to_smp_group) | ||
53 | 99 | ||
100 | ENTRY(ll_enable_coherency) | ||
101 | /* | ||
102 | * As r0 is not modified by ll_get_coherency_base() and | ||
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. | ||
107 | */ | ||
108 | mov r0, lr | ||
109 | bl ll_get_coherency_base | ||
110 | bl ll_get_coherency_cpumask | ||
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 | ||
54 | dsb | 119 | dsb |
55 | |||
56 | mov r0, #0 | 120 | mov r0, #0 |
57 | mov pc, lr | 121 | mov pc, lr |
58 | ENDPROC(ll_set_cpu_coherent) | 122 | ENDPROC(ll_enable_coherency) |
123 | |||
124 | ENTRY(ll_disable_coherency) | ||
125 | /* | ||
126 | * As r0 is not modified by ll_get_coherency_base() and | ||
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. | ||
131 | */ | ||
132 | mov r0, lr | ||
133 | bl ll_get_coherency_base | ||
134 | bl ll_get_coherency_cpumask | ||
135 | mov lr, r0 | ||
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 | ||
144 | mov pc, lr | ||
145 | ENDPROC(ll_disable_coherency) | ||
146 | |||
147 | .align 2 | ||
148 | 3: | ||
149 | .long coherency_phys_base - . | ||