2 * Copyright © 2019 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.
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.
19 #ifndef _AO_ARCH_FUNCS_H_
20 #define _AO_ARCH_FUNCS_H_
22 #define AO_MODE_PULL_NONE 0
23 #define AO_MODE_PULL_UP 1
24 #define AO_MODE_PULL_DOWN 2
26 static inline void ao_enable_port(struct samd21_port *port)
29 samd21_pm.apbbmask |= (1UL << SAMD21_PM_APBBMASK_PORT);
32 static inline void ao_disable_port(struct samd21_port *port)
35 samd21_pm.apbbmask &= ~(1UL << SAMD21_PM_APBBMASK_PORT);
39 ao_gpio_set(struct samd21_port *port, uint8_t bit, uint8_t v)
42 port->outset = (1 << bit);
44 port->outclr = (1 << bit);
48 ao_gpio_get(struct samd21_port *port, uint8_t bit)
50 return (port->in >> bit) & 1;
54 ao_gpio_dir_set(struct samd21_port *port, uint8_t bit, bool output)
57 port->dirset = (1 << bit);
59 port->dirclr = (1 << bit);
63 ao_gpio_set_mode(struct samd21_port *port, uint8_t bit, uint32_t mode)
67 if (mode != AO_MODE_PULL_NONE) {
68 pincfg |= (1 << SAMD21_PORT_PINCFG_PULLEN);
69 ao_gpio_set(port, bit, mode == AO_MODE_PULL_UP);
72 samd21_port_pincfg_set(port, bit,
73 (0 << SAMD21_PORT_PINCFG_DRVSTR) |
74 (1 << SAMD21_PORT_PINCFG_PULLEN) |
75 (0 << SAMD21_PORT_PINCFG_INEN) |
76 (0 << SAMD21_PORT_PINCFG_PMUXEN),
81 ao_enable_output(struct samd21_port *port, uint8_t pin, uint8_t v)
84 ao_gpio_set(port, pin, v);
85 samd21_port_dir_set(port, pin, SAMD21_PORT_DIR_OUT);
86 samd21_port_pincfg_set(port, pin,
87 (1 << SAMD21_PORT_PINCFG_DRVSTR) |
88 (1 << SAMD21_PORT_PINCFG_PULLEN) |
89 (1 << SAMD21_PORT_PINCFG_INEN),
90 (0 << SAMD21_PORT_PINCFG_DRVSTR) |
91 (0 << SAMD21_PORT_PINCFG_PULLEN) |
92 (0 << SAMD21_PORT_PINCFG_INEN));
96 ao_enable_input(struct samd21_port *port, uint8_t pin, uint32_t mode)
99 samd21_port_dir_set(port, pin, SAMD21_PORT_DIR_IN);
102 pincfg = ((0 << SAMD21_PORT_PINCFG_DRVSTR) |
103 (0 << SAMD21_PORT_PINCFG_PULLEN) |
104 (1 << SAMD21_PORT_PINCFG_INEN) |
105 (0 << SAMD21_PORT_PINCFG_PMUXEN));
107 if (mode != AO_MODE_PULL_NONE) {
108 pincfg |= (1 << SAMD21_PORT_PINCFG_PULLEN);
109 ao_gpio_set(port, pin, mode == AO_MODE_PULL_UP);
112 samd21_port_pincfg_set(port, pin,
113 (1 << SAMD21_PORT_PINCFG_DRVSTR) |
114 (1 << SAMD21_PORT_PINCFG_PULLEN) |
115 (1 << SAMD21_PORT_PINCFG_INEN) |
116 (1 << SAMD21_PORT_PINCFG_PMUXEN),
121 ao_enable_cs(struct samd21_port *port, uint8_t pin)
123 ao_enable_output(port, pin, 1);
126 #define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
128 typedef uint32_t ao_arch_irq_t;
130 static inline uint32_t
131 ao_arch_irqsave(void) {
133 asm("mrs %0,primask" : "=&r" (primask));
134 ao_arch_block_interrupts();
139 ao_arch_irqrestore(uint32_t primask) {
140 asm("msr primask,%0" : : "r" (primask));
144 ao_arch_memory_barrier(void) {
145 asm volatile("" ::: "memory");
150 ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
152 uint32_t a = (uint32_t) start;
155 /* Return address (goes into LR) */
158 /* Clear register values r0-r7 */
166 /* PRIMASK with interrupts enabled */
172 static inline void ao_arch_save_regs(void) {
173 /* Save general registers */
174 asm("push {r0-r7,lr}\n");
181 asm("mrs r0,primask");
185 static inline void ao_arch_save_stack(void) {
187 asm("mov %0,sp" : "=&r" (sp) );
188 ao_cur_task->sp32 = (sp);
189 if (sp < &ao_cur_task->stack32[0])
190 ao_panic (AO_PANIC_STACK);
193 static inline void ao_arch_restore_stack(void) {
195 asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
197 /* Restore PRIMASK */
199 asm("msr primask,r0");
203 asm("msr apsr_nczvq,r0");
205 /* Restore general registers */
206 asm("pop {r0-r7,pc}\n");
209 #ifndef HAS_SAMPLE_PROFILE
210 #define HAS_SAMPLE_PROFILE 0
213 #if !HAS_SAMPLE_PROFILE
214 #define HAS_ARCH_START_SCHEDULER 1
216 static inline void ao_arch_start_scheduler(void) {
220 asm("mrs %0,msp" : "=&r" (sp));
221 asm("msr psp,%0" : : "r" (sp));
222 asm("mrs %0,control" : "=&r" (control));
224 asm("msr control,%0" : : "r" (control));
229 #define ao_arch_isr_stack()
233 #define ao_arch_wait_interrupt() do { \
235 ao_arch_release_interrupts(); \
236 asm(".global ao_idle_loc\nao_idle_loc:"); \
237 ao_arch_block_interrupts(); \
240 #define ao_arch_critical(b) do { \
241 uint32_t __mask = ao_arch_irqsave(); \
242 do { b } while (0); \
243 ao_arch_irqrestore(__mask); \
246 /* ao_serial_samd21.c */
248 #if USE_SERIAL_0_FLOW && USE_SERIAL_0_SW_FLOW || USE_SERIAL_1_FLOW && USE_SERIAL_1_SW_FLOW
249 #define HAS_SERIAL_SW_FLOW 1
251 #define HAS_SERIAL_SW_FLOW 0
254 #if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW
255 #define USE_SERIAL_1_HW_FLOW 1
258 #if USE_SERIAL_0_FLOW && !USE_SERIAL_0_SW_FLOW
259 #define USE_SERIAL_0_HW_FLOW 1
262 #if USE_SERIAL_0_HW_FLOW || USE_SERIAL_1_HW_FLOW
263 #define HAS_SERIAL_HW_FLOW 1
265 #define HAS_SERIAL_HW_FLOW 0
268 struct ao_samd21_usart {
269 struct ao_fifo rx_fifo;
270 struct ao_fifo tx_fifo;
271 struct samd21_sercom *reg;
274 #if HAS_SERIAL_SW_FLOW
275 /* RTS - 0 if we have FIFO space, 1 if not
276 * CTS - 0 if we can send, 0 if not
278 struct samd21_port *gpio_rts;
279 struct samd21_port *gpio_cts;
287 extern struct ao_samd21_usart ao_samd21_usart0;
291 ao_serial_init(void);
293 /* ao_usb_samd21.c */
297 ao_usb_out_hook(uint8_t *buffer, uint16_t count);
302 #endif /* _AO_ARCH_FUNCS_H_ */