diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/system-arm.h | 241 |
1 files changed, 157 insertions, 84 deletions
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h index c383121b46..0608f50a02 100644 --- a/firmware/target/arm/system-arm.h +++ b/firmware/target/arm/system-arm.h | |||
@@ -21,29 +21,85 @@ | |||
21 | #ifndef SYSTEM_ARM_H | 21 | #ifndef SYSTEM_ARM_H |
22 | #define SYSTEM_ARM_H | 22 | #define SYSTEM_ARM_H |
23 | 23 | ||
24 | /* Common to all ARM_ARCH */ | ||
24 | #define nop \ | 25 | #define nop \ |
25 | asm volatile ("nop") | 26 | asm volatile ("nop") |
26 | 27 | ||
27 | void __div0(void); | 28 | void __div0(void); |
28 | 29 | ||
29 | /* This gets too complicated otherwise with all the ARM variation and would | 30 | #define IRQ_ENABLED 0x00 |
30 | have conflicts with another system-target.h elsewhere so include a | 31 | #define IRQ_DISABLED 0x80 |
31 | subheader from here. */ | 32 | #define IRQ_STATUS 0x80 |
33 | #define FIQ_ENABLED 0x00 | ||
34 | #define FIQ_DISABLED 0x40 | ||
35 | #define FIQ_STATUS 0x40 | ||
36 | #define IRQ_FIQ_ENABLED 0x00 | ||
37 | #define IRQ_FIQ_DISABLED 0xc0 | ||
38 | #define IRQ_FIQ_STATUS 0xc0 | ||
39 | #define HIGHEST_IRQ_LEVEL IRQ_DISABLED | ||
40 | |||
41 | #define set_irq_level(status) \ | ||
42 | set_interrupt_status((status), IRQ_STATUS) | ||
43 | #define set_fiq_status(status) \ | ||
44 | set_interrupt_status((status), FIQ_STATUS) | ||
45 | |||
46 | #define disable_irq_save() \ | ||
47 | disable_interrupt_save(IRQ_STATUS) | ||
48 | #define disable_fiq_save() \ | ||
49 | disable_interrupt_save(FIQ_STATUS) | ||
50 | |||
51 | #define restore_irq(cpsr) \ | ||
52 | restore_interrupt(cpsr) | ||
53 | #define restore_fiq(cpsr) \ | ||
54 | restore_interrupt(cpsr) | ||
55 | |||
56 | #define disable_irq() \ | ||
57 | disable_interrupt(IRQ_STATUS) | ||
58 | #define enable_irq() \ | ||
59 | enable_interrupt(IRQ_STATUS) | ||
60 | #define disable_fiq() \ | ||
61 | disable_interrupt(FIQ_STATUS) | ||
62 | #define enable_fiq() \ | ||
63 | enable_interrupt(FIQ_STATUS) | ||
64 | |||
65 | /* Core-level interrupt masking */ | ||
66 | |||
67 | static inline int set_interrupt_status(int status, int mask) | ||
68 | { | ||
69 | unsigned long cpsr; | ||
70 | int oldstatus; | ||
71 | /* Read the old levels and set the new ones */ | ||
72 | asm volatile ( | ||
73 | "mrs %1, cpsr \n" | ||
74 | "bic %0, %1, %[mask] \n" | ||
75 | "orr %0, %0, %2 \n" | ||
76 | "msr cpsr_c, %0 \n" | ||
77 | : "=&r,r"(cpsr), "=&r,r"(oldstatus) | ||
78 | : "r,i"(status & mask), [mask]"i,i"(mask)); | ||
79 | |||
80 | return oldstatus; | ||
81 | } | ||
32 | 82 | ||
83 | static inline void restore_interrupt(int cpsr) | ||
84 | { | ||
85 | /* Set cpsr_c from value returned by disable_interrupt_save | ||
86 | * or set_interrupt_status */ | ||
87 | asm volatile ("msr cpsr_c, %0" : : "r"(cpsr)); | ||
88 | } | ||
89 | |||
90 | /* ARM_ARCH version section for architecture*/ | ||
91 | |||
92 | #if ARM_ARCH >= 6 | ||
33 | static inline uint16_t swap16(uint16_t value) | 93 | static inline uint16_t swap16(uint16_t value) |
34 | /* | 94 | /* |
35 | result[15..8] = value[ 7..0]; | 95 | result[15..8] = value[ 7..0]; |
36 | result[ 7..0] = value[15..8]; | 96 | result[ 7..0] = value[15..8]; |
37 | */ | 97 | */ |
38 | { | 98 | { |
39 | #if ARM_ARCH >= 6 | ||
40 | uint32_t retval; | 99 | uint32_t retval; |
41 | asm volatile ("revsh %0, %1" /* xxAB */ | 100 | asm volatile ("revsh %0, %1" /* xxAB */ |
42 | : "=r"(retval) : "r"((uint32_t)value)); /* xxBA */ | 101 | : "=r"(retval) : "r"((uint32_t)value)); /* xxBA */ |
43 | return retval; | 102 | return retval; |
44 | #else | ||
45 | return (value >> 8) | (value << 8); | ||
46 | #endif | ||
47 | } | 103 | } |
48 | 104 | ||
49 | static inline uint32_t swap32(uint32_t value) | 105 | static inline uint32_t swap32(uint32_t value) |
@@ -54,14 +110,104 @@ static inline uint32_t swap32(uint32_t value) | |||
54 | result[ 7.. 0] = value[31..24]; | 110 | result[ 7.. 0] = value[31..24]; |
55 | */ | 111 | */ |
56 | { | 112 | { |
57 | #if ARM_ARCH >= 6 | ||
58 | uint32_t retval; | 113 | uint32_t retval; |
59 | asm volatile ("rev %0, %1" /* ABCD */ | 114 | asm volatile ("rev %0, %1" /* ABCD */ |
60 | : "=r"(retval) : "r"(value)); /* DCBA */ | 115 | : "=r"(retval) : "r"(value)); /* DCBA */ |
61 | return retval; | 116 | return retval; |
62 | #else | 117 | } |
63 | uint32_t tmp; | 118 | |
119 | static inline uint32_t swap_odd_even32(uint32_t value) | ||
120 | { | ||
121 | /* | ||
122 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | ||
123 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | ||
124 | */ | ||
125 | uint32_t retval; | ||
126 | asm volatile ("rev16 %0, %1" /* ABCD */ | ||
127 | : "=r"(retval) : "r"(value)); /* BADC */ | ||
128 | return retval; | ||
129 | } | ||
64 | 130 | ||
131 | static inline void enable_interrupt(int mask) | ||
132 | { | ||
133 | /* Clear I and/or F disable bit */ | ||
134 | /* mask is expected to be constant and so only relevent branch | ||
135 | * is preserved */ | ||
136 | switch (mask & IRQ_FIQ_STATUS) | ||
137 | { | ||
138 | case IRQ_STATUS: | ||
139 | asm volatile ("cpsie i"); | ||
140 | break; | ||
141 | case FIQ_STATUS: | ||
142 | asm volatile ("cpsie f"); | ||
143 | break; | ||
144 | case IRQ_FIQ_STATUS: | ||
145 | asm volatile ("cpsie if"); | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static inline void disable_interrupt(int mask) | ||
151 | { | ||
152 | /* Set I and/or F disable bit */ | ||
153 | /* mask is expected to be constant and so only relevent branch | ||
154 | * is preserved */ | ||
155 | switch (mask & IRQ_FIQ_STATUS) | ||
156 | { | ||
157 | case IRQ_STATUS: | ||
158 | asm volatile ("cpsid i"); | ||
159 | break; | ||
160 | case FIQ_STATUS: | ||
161 | asm volatile ("cpsid f"); | ||
162 | break; | ||
163 | case IRQ_FIQ_STATUS: | ||
164 | asm volatile ("cpsid if"); | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static inline int disable_interrupt_save(int mask) | ||
170 | { | ||
171 | /* Set I and/or F disable bit and return old cpsr value */ | ||
172 | int cpsr; | ||
173 | /* mask is expected to be constant and so only relevent branch | ||
174 | * is preserved */ | ||
175 | asm volatile("mrs %0, cpsr" : "=r"(cpsr)); | ||
176 | switch (mask & IRQ_FIQ_STATUS) | ||
177 | { | ||
178 | case IRQ_STATUS: | ||
179 | asm volatile ("cpsid i"); | ||
180 | break; | ||
181 | case FIQ_STATUS: | ||
182 | asm volatile ("cpsid f"); | ||
183 | break; | ||
184 | case IRQ_FIQ_STATUS: | ||
185 | asm volatile ("cpsid if"); | ||
186 | break; | ||
187 | } | ||
188 | return cpsr; | ||
189 | } | ||
190 | |||
191 | #else /* ARM_ARCH < 6 */ | ||
192 | |||
193 | static inline uint16_t swap16(uint16_t value) | ||
194 | /* | ||
195 | result[15..8] = value[ 7..0]; | ||
196 | result[ 7..0] = value[15..8]; | ||
197 | */ | ||
198 | { | ||
199 | return (value >> 8) | (value << 8); | ||
200 | } | ||
201 | |||
202 | static inline uint32_t swap32(uint32_t value) | ||
203 | /* | ||
204 | result[31..24] = value[ 7.. 0]; | ||
205 | result[23..16] = value[15.. 8]; | ||
206 | result[15.. 8] = value[23..16]; | ||
207 | result[ 7.. 0] = value[31..24]; | ||
208 | */ | ||
209 | { | ||
210 | uint32_t tmp; | ||
65 | asm volatile ( | 211 | asm volatile ( |
66 | "eor %1, %0, %0, ror #16 \n\t" | 212 | "eor %1, %0, %0, ror #16 \n\t" |
67 | "bic %1, %1, #0xff0000 \n\t" | 213 | "bic %1, %1, #0xff0000 \n\t" |
@@ -70,7 +216,6 @@ static inline uint32_t swap32(uint32_t value) | |||
70 | : "+r" (value), "=r" (tmp) | 216 | : "+r" (value), "=r" (tmp) |
71 | ); | 217 | ); |
72 | return value; | 218 | return value; |
73 | #endif | ||
74 | } | 219 | } |
75 | 220 | ||
76 | static inline uint32_t swap_odd_even32(uint32_t value) | 221 | static inline uint32_t swap_odd_even32(uint32_t value) |
@@ -79,14 +224,7 @@ static inline uint32_t swap_odd_even32(uint32_t value) | |||
79 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] | 224 | result[31..24],[15.. 8] = value[23..16],[ 7.. 0] |
80 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] | 225 | result[23..16],[ 7.. 0] = value[31..24],[15.. 8] |
81 | */ | 226 | */ |
82 | #if ARM_ARCH >= 6 | ||
83 | uint32_t retval; | ||
84 | asm volatile ("rev16 %0, %1" /* ABCD */ | ||
85 | : "=r"(retval) : "r"(value)); /* BADC */ | ||
86 | return retval; | ||
87 | #else | ||
88 | uint32_t tmp; | 227 | uint32_t tmp; |
89 | |||
90 | asm volatile ( /* ABCD */ | 228 | asm volatile ( /* ABCD */ |
91 | "bic %1, %0, #0x00ff00 \n\t" /* AB.D */ | 229 | "bic %1, %0, #0x00ff00 \n\t" /* AB.D */ |
92 | "bic %0, %0, #0xff0000 \n\t" /* A.CD */ | 230 | "bic %0, %0, #0xff0000 \n\t" /* A.CD */ |
@@ -95,42 +233,6 @@ static inline uint32_t swap_odd_even32(uint32_t value) | |||
95 | : "+r" (value), "=r" (tmp) /* BADC */ | 233 | : "+r" (value), "=r" (tmp) /* BADC */ |
96 | ); | 234 | ); |
97 | return value; | 235 | return value; |
98 | #endif | ||
99 | } | ||
100 | |||
101 | /* Core-level interrupt masking */ | ||
102 | |||
103 | /* This one returns the old status */ | ||
104 | #define IRQ_ENABLED 0x00 | ||
105 | #define IRQ_DISABLED 0x80 | ||
106 | #define IRQ_STATUS 0x80 | ||
107 | #define FIQ_ENABLED 0x00 | ||
108 | #define FIQ_DISABLED 0x40 | ||
109 | #define FIQ_STATUS 0x40 | ||
110 | #define IRQ_FIQ_ENABLED 0x00 | ||
111 | #define IRQ_FIQ_DISABLED 0xc0 | ||
112 | #define IRQ_FIQ_STATUS 0xc0 | ||
113 | #define HIGHEST_IRQ_LEVEL IRQ_DISABLED | ||
114 | |||
115 | #define set_irq_level(status) \ | ||
116 | set_interrupt_status((status), IRQ_STATUS) | ||
117 | #define set_fiq_status(status) \ | ||
118 | set_interrupt_status((status), FIQ_STATUS) | ||
119 | |||
120 | static inline int set_interrupt_status(int status, int mask) | ||
121 | { | ||
122 | unsigned long cpsr; | ||
123 | int oldstatus; | ||
124 | /* Read the old levels and set the new ones */ | ||
125 | asm volatile ( | ||
126 | "mrs %1, cpsr \n" | ||
127 | "bic %0, %1, %[mask] \n" | ||
128 | "orr %0, %0, %2 \n" | ||
129 | "msr cpsr_c, %0 \n" | ||
130 | : "=&r,r"(cpsr), "=&r,r"(oldstatus) | ||
131 | : "r,i"(status & mask), [mask]"i,i"(mask)); | ||
132 | |||
133 | return oldstatus; | ||
134 | } | 236 | } |
135 | 237 | ||
136 | static inline void enable_interrupt(int mask) | 238 | static inline void enable_interrupt(int mask) |
@@ -155,18 +257,6 @@ static inline void disable_interrupt(int mask) | |||
155 | : "=&r"(tmp) : "i"(mask)); | 257 | : "=&r"(tmp) : "i"(mask)); |
156 | } | 258 | } |
157 | 259 | ||
158 | #define disable_irq() \ | ||
159 | disable_interrupt(IRQ_STATUS) | ||
160 | |||
161 | #define enable_irq() \ | ||
162 | enable_interrupt(IRQ_STATUS) | ||
163 | |||
164 | #define disable_fiq() \ | ||
165 | disable_interrupt(FIQ_STATUS) | ||
166 | |||
167 | #define enable_fiq() \ | ||
168 | enable_interrupt(FIQ_STATUS) | ||
169 | |||
170 | static inline int disable_interrupt_save(int mask) | 260 | static inline int disable_interrupt_save(int mask) |
171 | { | 261 | { |
172 | /* Set I and/or F disable bit and return old cpsr value */ | 262 | /* Set I and/or F disable bit and return old cpsr value */ |
@@ -180,23 +270,6 @@ static inline int disable_interrupt_save(int mask) | |||
180 | return cpsr; | 270 | return cpsr; |
181 | } | 271 | } |
182 | 272 | ||
183 | #define disable_irq_save() \ | 273 | #endif /* ARM_ARCH */ |
184 | disable_interrupt_save(IRQ_STATUS) | ||
185 | |||
186 | #define disable_fiq_save() \ | ||
187 | disable_interrupt_save(FIQ_STATUS) | ||
188 | |||
189 | static inline void restore_interrupt(int cpsr) | ||
190 | { | ||
191 | /* Set cpsr_c from value returned by disable_interrupt_save | ||
192 | * or set_interrupt_status */ | ||
193 | asm volatile ("msr cpsr_c, %0" : : "r"(cpsr)); | ||
194 | } | ||
195 | |||
196 | #define restore_irq(cpsr) \ | ||
197 | restore_interrupt(cpsr) | ||
198 | |||
199 | #define restore_fiq(cpsr) \ | ||
200 | restore_interrupt(cpsr) | ||
201 | 274 | ||
202 | #endif /* SYSTEM_ARM_H */ | 275 | #endif /* SYSTEM_ARM_H */ |