altos/stm32f1: More stm32f103 work
[fw/altos] / src / stm32f1 / ao_arch_funcs.h
1 /*
2  * Copyright © 2023 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #ifndef _AO_ARCH_FUNCS_H_
20 #define _AO_ARCH_FUNCS_H_
21
22 static inline void
23 ao_enable_port(struct stm_gpio *port)
24 {
25         if ((port) == &stm_gpioa)
26                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPAEN);
27         else if ((port) == &stm_gpiob)
28                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPBEN);
29         else if ((port) == &stm_gpioc)
30                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPCEN);
31         else if ((port) == &stm_gpiod)
32                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPDEN);
33         else if ((port) == &stm_gpioe)
34                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_IOPEEN);
35 }
36
37 static inline void
38 ao_disable_port(struct stm_gpio *port)
39 {
40         if ((port) == &stm_gpioa)
41                 stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPAEN);
42         else if ((port) == &stm_gpiob)
43                 stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPBEN);
44         else if ((port) == &stm_gpioc)
45                 stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPCEN);
46         else if ((port) == &stm_gpiod)
47                 stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPDEN);
48         else if ((port) == &stm_gpioe)
49                 stm_rcc.apb2enr &= ~(1UL << STM_RCC_APB2ENR_IOPEEN);
50 }
51
52 #define ao_gpio_set(port, bit, v) stm_gpio_set(port, bit, v)
53
54 #define ao_gpio_get(port, bit) stm_gpio_get(port, bit)
55
56 #define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits)
57
58 #define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask)
59
60 #define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits);
61
62 #define ao_gpio_get_all(port) stm_gpio_get_all(port)
63
64 static inline void
65 ao_enable_output(struct stm_gpio *port, int bit, uint8_t v)
66 {
67         ao_enable_port(port);
68         ao_gpio_set(port, bit, v);
69         stm_gpio_conf(port, bit,
70                       STM_GPIO_CR_MODE_OUTPUT_10MHZ,
71                       STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL);
72 }
73
74 #if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW
75 #define HAS_SERIAL_SW_FLOW 1
76 #else
77 #define HAS_SERIAL_SW_FLOW 0
78 #endif
79
80 #if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_FLOW && !USE_SERIAL_3_SW_FLOW
81 #define HAS_SERIAL_HW_FLOW 1
82 #else
83 #define HAS_SERIAL_HW_FLOW 0
84 #endif
85
86 /* ao_serial_stm.c */
87 struct ao_stm_usart {
88         struct ao_fifo          rx_fifo;
89         struct ao_fifo          tx_fifo;
90         struct stm_usart        *reg;
91         uint8_t                 tx_running;
92         uint8_t                 draining;
93 #if HAS_SERIAL_SW_FLOW
94         /* RTS - 0 if we have FIFO space, 1 if not
95          * CTS - 0 if we can send, 0 if not
96          */
97         struct stm_gpio         *gpio_rts;
98         struct stm_gpio         *gpio_cts;
99         uint8_t                 pin_rts;
100         uint8_t                 pin_cts;
101         uint8_t                 rts;
102 #endif
103 };
104
105 void
106 ao_debug_out(char c);
107
108 #if HAS_SERIAL_1
109 extern struct ao_stm_usart      ao_stm_usart1;
110 #endif
111
112 #if HAS_SERIAL_2
113 extern struct ao_stm_usart      ao_stm_usart2;
114 #endif
115
116 #if HAS_SERIAL_3
117 extern struct ao_stm_usart      ao_stm_usart3;
118 #endif
119
120 #define ARM_PUSH32(stack, val)  (*(--(stack)) = (val))
121
122 typedef uint32_t        ao_arch_irq_t;
123
124 static inline void
125 ao_arch_block_interrupts(void) {
126 #ifdef AO_NONMASK_INTERRUPTS
127         asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK));
128 #else
129         asm("cpsid i");
130 #endif
131 }
132
133 static inline void
134 ao_arch_release_interrupts(void) {
135 #ifdef AO_NONMASK_INTERRUPTS
136         asm("msr basepri,%0" : : "r" (0x0));
137 #else
138         asm("cpsie i");
139 #endif
140 }
141
142 static inline uint32_t
143 ao_arch_irqsave(void) {
144         uint32_t        val;
145 #ifdef AO_NONMASK_INTERRUPTS
146         asm("mrs %0,basepri" : "=r" (val));
147 #else
148         asm("mrs %0,primask" : "=r" (val));
149 #endif
150         ao_arch_block_interrupts();
151         return val;
152 }
153
154 static inline void
155 ao_arch_irqrestore(uint32_t basepri) {
156 #ifdef AO_NONMASK_INTERRUPTS
157         asm("msr basepri,%0" : : "r" (basepri));
158 #else
159         asm("msr primask,%0" : : "r" (basepri));
160 #endif
161 }
162
163 static inline void
164 ao_arch_memory_barrier(void) {
165         asm volatile("" ::: "memory");
166 }
167
168 static inline void
169 ao_arch_irq_check(void) {
170 #ifdef AO_NONMASK_INTERRUPTS
171         uint32_t        basepri;
172         asm("mrs %0,basepri" : "=r" (basepri));
173         if (basepri == 0)
174                 ao_panic(AO_PANIC_IRQ);
175 #else
176         uint32_t        primask;
177         asm("mrs %0,primask" : "=r" (primask));
178         if ((primask & 1) == 0)
179                 ao_panic(AO_PANIC_IRQ);
180 #endif
181 }
182
183 #if HAS_TASK
184 static inline void
185 ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
186 {
187         uint32_t        a = (uint32_t) start;
188         int             i;
189
190         /* Return address (goes into LR) */
191         ARM_PUSH32(sp, a);
192
193         /* Clear register values r0-r12 */
194         i = 13;
195         while (i--)
196                 ARM_PUSH32(sp, 0);
197
198         /* APSR */
199         ARM_PUSH32(sp, 0);
200
201         /* BASEPRI with interrupts enabled */
202         ARM_PUSH32(sp, 0);
203
204         task->sp32 = sp;
205 }
206
207 static inline void ao_arch_save_regs(void) {
208         /* Save general registers */
209         asm("push {r0-r12,lr}\n");
210
211         /* Save APSR */
212         asm("mrs r0,apsr");
213         asm("push {r0}");
214
215 #ifdef AO_NONMASK_INTERRUPTS
216         /* Save BASEPRI */
217         asm("mrs r0,basepri");
218 #else
219         /* Save PRIMASK */
220         asm("mrs r0,primask");
221 #endif
222         asm("push {r0}");
223 }
224
225 static inline void ao_arch_save_stack(void) {
226         uint32_t        *sp;
227         asm("mov %0,sp" : "=&r" (sp) );
228         ao_cur_task->sp32 = (sp);
229 }
230
231 static inline void ao_arch_restore_stack(void) {
232         /* Switch stacks */
233         asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
234
235 #ifdef AO_NONMASK_INTERRUPTS
236         /* Restore BASEPRI */
237         asm("pop {r0}");
238         asm("msr basepri,r0");
239 #else
240         /* Restore PRIMASK */
241         asm("pop {r0}");
242         asm("msr primask,r0");
243 #endif
244
245         /* Restore APSR */
246         asm("pop {r0}");
247         asm("msr apsr_nczvq,r0");
248
249         /* Restore general registers */
250         asm("pop {r0-r12,lr}\n");
251
252         /* Return to calling function */
253         asm("bx lr");
254 }
255 #define HAS_ARCH_START_SCHEDULER        1
256
257 static inline void ao_arch_start_scheduler(void) {
258         uint32_t        sp;
259         uint32_t        control;
260
261         asm("mrs %0,msp" : "=&r" (sp));
262         asm("msr psp,%0" : : "r" (sp));
263         asm("mrs %0,control" : "=r" (control));
264         control |= (1 << 1);
265         asm("msr control,%0" : : "r" (control));
266         asm("isb");
267 }
268
269 #define ao_arch_isr_stack()
270
271 #endif /* HAS_TASK */
272
273 static inline void
274 ao_arch_wait_interrupt(void) {
275 #ifdef AO_NONMASK_INTERRUPTS
276         asm(
277             "dsb\n"                     /* Serialize data */
278             "isb\n"                     /* Serialize instructions */
279             "cpsid i\n"                 /* Block all interrupts */
280             "msr basepri,%0\n"          /* Allow all interrupts through basepri */
281             "wfi\n"                     /* Wait for an interrupt */
282             "cpsie i\n"                 /* Allow all interrupts */
283             "msr basepri,%1\n"          /* Block interrupts through basepri */
284             : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK));
285 #else
286         asm("\twfi\n");
287         ao_arch_release_interrupts();
288         ao_arch_block_interrupts();
289 #endif
290 }
291
292 #define ao_arch_critical(b) do {                        \
293                 uint32_t __mask = ao_arch_irqsave();    \
294                 do { b } while (0);                     \
295                 ao_arch_irqrestore(__mask);             \
296         } while (0)
297
298 #define ao_arch_reboot() \
299         (stm_scb.aircr = ((STM_SCB_AIRCR_VECTKEY_KEY << STM_SCB_AIRCR_VECTKEY) | \
300                           (1 << STM_SCB_AIRCR_SYSRESETREQ)))
301
302 #endif /* _AO_ARCH_FUNCS_H_ */