2 * Copyright © 2018 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 #ifndef _AO_ARCH_FUNCS_H_
16 #define _AO_ARCH_FUNCS_H_
20 #define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
22 typedef uint32_t ao_arch_irq_t;
25 ao_arch_block_interrupts(void) {
26 #ifdef AO_NONMASK_INTERRUPTS
27 asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK));
34 ao_arch_release_interrupts(void) {
35 #ifdef AO_NONMASK_INTERRUPTS
36 asm("msr basepri,%0" : : "r" (0x0));
42 static inline uint32_t
43 ao_arch_irqsave(void) {
45 #ifdef AO_NONMASK_INTERRUPTS
46 asm("mrs %0,basepri" : "=r" (val));
48 asm("mrs %0,primask" : "=r" (val));
50 ao_arch_block_interrupts();
55 ao_arch_irqrestore(uint32_t basepri) {
56 #ifdef AO_NONMASK_INTERRUPTS
57 asm("msr basepri,%0" : : "r" (basepri));
59 asm("msr primask,%0" : : "r" (basepri));
64 ao_arch_memory_barrier(void) {
65 asm volatile("" ::: "memory");
69 ao_arch_irq_check(void) {
70 #ifdef AO_NONMASK_INTERRUPTS
72 asm("mrs %0,basepri" : "=r" (basepri));
74 ao_panic(AO_PANIC_IRQ);
77 asm("mrs %0,primask" : "=r" (primask));
78 if ((primask & 1) == 0)
79 ao_panic(AO_PANIC_IRQ);
85 ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
87 uint32_t a = (uint32_t) start;
90 /* Return address (goes into LR) */
93 /* Clear register values r0-r12 */
101 /* Clear register values s0-s31 */
109 /* BASEPRI with interrupts enabled */
115 static inline void ao_arch_save_regs(void) {
116 /* Save general registers */
117 asm("push {r0-r12,lr}");
123 /* Save FPU registers */
124 asm("vpush {s0-s15}");
125 asm("vpush {s16-s31}");
128 asm("vmrs r0,fpscr");
131 #ifdef AO_NONMASK_INTERRUPTS
133 asm("mrs r0,basepri");
136 asm("mrs r0,primask");
141 static inline void ao_arch_save_stack(void) {
143 asm("mov %0,sp" : "=&r" (sp) );
144 ao_cur_task->sp32 = (sp);
147 static inline void ao_arch_restore_stack(void) {
149 asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
151 #ifdef AO_NONMASK_INTERRUPTS
152 /* Restore BASEPRI */
154 asm("msr basepri,r0");
156 /* Restore PRIMASK */
158 asm("msr primask,r0");
163 asm("vmsr fpscr,r0");
165 /* Restore FPU registers */
166 asm("vpop {s16-s31}");
167 asm("vpop {s0-s15}");
171 asm("msr apsr_nczvq,r0");
173 /* Restore general registers */
174 asm("pop {r0-r12,lr}\n");
176 /* Return to calling function */
180 #ifndef HAS_SAMPLE_PROFILE
181 #define HAS_SAMPLE_PROFILE 0
185 #define HAS_ARCH_VALIDATE_CUR_STACK 1
188 ao_validate_cur_stack(void)
192 asm("mrs %0,psp" : "=&r" (psp));
194 psp <= ao_cur_task->stack &&
195 psp >= ao_cur_task->stack - 256)
196 ao_panic(AO_PANIC_STACK);
200 #if !HAS_SAMPLE_PROFILE
201 #define HAS_ARCH_START_SCHEDULER 1
203 static inline void ao_arch_start_scheduler(void) {
207 asm("mrs %0,msp" : "=&r" (sp));
208 asm("msr psp,%0" : : "r" (sp));
209 asm("mrs %0,control" : "=r" (control));
211 asm("msr control,%0" : : "r" (control));
216 #define ao_arch_isr_stack()
221 ao_arch_wait_interrupt(void) {
222 #ifdef AO_NONMASK_INTERRUPTS
224 "dsb\n" /* Serialize data */
225 "isb\n" /* Serialize instructions */
226 "cpsid i\n" /* Block all interrupts */
227 "msr basepri,%0\n" /* Allow all interrupts through basepri */
228 "wfi\n" /* Wait for an interrupt */
229 "cpsie i\n" /* Allow all interrupts */
230 "msr basepri,%1\n" /* Block interrupts through basepri */
231 : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK));
234 ao_arch_release_interrupts();
235 ao_arch_block_interrupts();
239 #define ao_arch_critical(b) do { \
240 uint32_t __mask = ao_arch_irqsave(); \
241 do { b } while (0); \
242 ao_arch_irqrestore(__mask); \
247 #define ao_power_register(gpio)
248 #define ao_power_unregister(gpio)
250 static inline void ao_enable_port(struct stm_gpio *port)
252 if ((port) == &stm_gpioa) {
253 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPAEN);
254 ao_power_register(&ao_power_gpioa);
255 } else if ((port) == &stm_gpiob) {
256 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPBEN);
257 ao_power_register(&ao_power_gpiob);
258 } else if ((port) == &stm_gpioc) {
259 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPCEN);
260 ao_power_register(&ao_power_gpioc);
261 } else if ((port) == &stm_gpiod) {
262 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPDEN);
263 ao_power_register(&ao_power_gpiod);
264 } else if ((port) == &stm_gpioe) {
265 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPEEN);
266 ao_power_register(&ao_power_gpioe);
267 } else if ((port) == &stm_gpiof) {
268 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPFEN);
269 ao_power_register(&ao_power_gpiof);
270 } else if ((port) == &stm_gpiog) {
271 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPGEN);
272 ao_power_register(&ao_power_gpiog);
273 } else if ((port) == &stm_gpioh) {
274 stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPHEN);
275 ao_power_register(&ao_power_gpioh);
279 static inline void ao_disable_port(struct stm_gpio *port)
281 if ((port) == &stm_gpioa) {
282 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPAEN);
283 ao_power_unregister(&ao_power_gpioa);
284 } else if ((port) == &stm_gpiob) {
285 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPBEN);
286 ao_power_unregister(&ao_power_gpiob);
287 } else if ((port) == &stm_gpioc) {
288 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPCEN);
289 ao_power_unregister(&ao_power_gpioc);
290 } else if ((port) == &stm_gpiod) {
291 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPDEN);
292 ao_power_unregister(&ao_power_gpiod);
293 } else if ((port) == &stm_gpioe) {
294 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPEEN);
295 ao_power_unregister(&ao_power_gpioe);
296 } else if ((port) == &stm_gpiof) {
297 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPFEN);
298 ao_power_unregister(&ao_power_gpiof);
299 } else if ((port) == &stm_gpiog) {
300 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPGEN);
301 ao_power_unregister(&ao_power_gpiog);
302 } else if ((port) == &stm_gpioh) {
303 stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPHEN);
304 ao_power_unregister(&ao_power_gpioh);
308 #define ao_gpio_set(port, bit, v) stm_gpio_set(port, bit, v)
310 #define ao_gpio_get(port, bit) stm_gpio_get(port, bit)
312 #define ao_enable_output(port,bit,v) do { \
313 ao_enable_port(port); \
314 ao_gpio_set(port, bit, v); \
315 stm_moder_set(port, bit, STM_MODER_OUTPUT);\
318 #define ao_gpio_set_mode(port,bit,mode) do { \
319 if (mode == AO_EXTI_MODE_PULL_UP) \
320 stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP); \
321 else if (mode == AO_EXTI_MODE_PULL_DOWN) \
322 stm_pupdr_set(port, bit, STM_PUPDR_PULL_DOWN); \
324 stm_pupdr_set(port, bit, STM_PUPDR_NONE); \
327 #define ao_enable_input(port,bit,mode) do { \
328 ao_enable_port(port); \
329 stm_moder_set(port, bit, STM_MODER_INPUT); \
330 ao_gpio_set_mode(port, bit, mode); \
342 ao_serial6_getchar(void);
345 ao_serial6_putchar(char c);
348 _ao_serial6_pollchar(void);
351 _ao_serial6_sleep_for(uint16_t timeout);
354 ao_serial6_set_speed(uint32_t speed);
357 ao_serial6_drain(void);
359 #endif /* _AO_ARCH_FUNCS_H_ */