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 /* ao_spi_samd21.c */
128 #define AO_SPI_INDEX_BIT 0
129 #define AO_SPI_INDEX_MASK 0x07
131 #define AO_SPI_CONFIG_BIT 4
132 #define AO_SPI_CONFIG_MASK (3 << AO_SPI_CONFIG_BIT)
134 #define AO_SPI_CPOL_BIT 6
135 #define AO_SPI_CPHA_BIT 7
137 #define AO_SPI_DOPO_BIT 8
138 #define AO_SPI_DOPO_MOSI_0_SCLK_1 (0 << AO_SPI_DOPO_BIT)
139 #define AO_SPI_DOPO_MOSI_2_SCLK_3 (1 << AO_SPI_DOPO_BIT)
140 #define AO_SPI_DOPO_MOSI_3_SCLK_1 (2 << AO_SPI_DOPO_BIT)
141 #define AO_SPI_DOPO_MOSI_0_SCLK_3 (3 << AO_SPI_DOPO_BIT)
142 #define AO_SPI_DOPO_MASK (3 << AO_SPI_DOPO_BIT)
144 #define AO_SPI_DIPO_BIT 10
145 #define AO_SPI_DIPO_MISO_0 (0 << AO_SPI_DIPO_BIT)
146 #define AO_SPI_DIPO_MISO_1 (1 << AO_SPI_DIPO_BIT)
147 #define AO_SPI_DIPO_MISO_2 (2 << AO_SPI_DIPO_BIT)
148 #define AO_SPI_DIPO_MISO_3 (3 << AO_SPI_DIPO_BIT)
149 #define AO_SPI_DIPO_MASK (3 << AO_SPI_DIPO_MASK)
151 #define AO_SPI_CONFIG_0 (0 << AO_SPI_CONFIG_BIT)
152 #define AO_SPI_CONFIG_1 (1 << AO_SPI_CONFIG_BIT)
153 #define AO_SPI_CONFIG_2 (2 << AO_SPI_CONFIG_BIT)
154 #define AO_SPI_CONFIG_3 (3 << AO_SPI_CONFIG_BIT)
156 #define AO_SPI_INDEX(id) ((uint8_t) ((id) & AO_SPI_INDEX_MASK))
157 #define AO_SPI_CONFIG(id) ((id) & AO_SPI_CONFIG_MASK)
158 #define AO_SPI_PIN_CONFIG(id) ((id) & (AO_SPI_INDEX_MASK | AO_SPI_CONFIG_MASK))
159 #define AO_SPI_CPOL(id) ((uint32_t) (((id) >> AO_SPI_CPOL_BIT) & 1))
160 #define AO_SPI_CPHA(id) ((uint32_t) (((id) >> AO_SPI_CPHA_BIT) & 1))
161 #define AO_SPI_DOPO(id) ((uint32_t) (((id) >> AO_SPI_DOPO_BIT) & 3))
162 #define AO_SPI_DIPO(id) ((uint32_t) (((id) >> AO_SPI_DIPO_BIT) & 3))
164 #define AO_SPI_MAKE_MODE(pol,pha) (((pol) << AO_SPI_CPOL_BIT) | ((pha) << AO_SPI_CPHA_BIT))
165 #define AO_SPI_MODE_0 AO_SPI_MAKE_MODE(0,0)
166 #define AO_SPI_MODE_1 AO_SPI_MAKE_MODE(0,1)
167 #define AO_SPI_MODE_2 AO_SPI_MAKE_MODE(1,0)
168 #define AO_SPI_MODE_3 AO_SPI_MAKE_MODE(1,1)
172 * PA08 SERCOM0.0 -> MOSI (DOPO 0)
173 * PA09 SERCOM0.1 -> SCLK (DOPO 0)
174 * PA10 SERCOM0.2 -> MISO (DIPO 2)
176 #define AO_SPI_0_PA08_PA09_PA10 (0 | AO_SPI_CONFIG_0 | \
177 AO_SPI_DOPO_MOSI_0_SCLK_1 | \
180 * PA04 SERCOM0.0 -> MOSI (DOPO 0)
181 * PA05 SERCOM0.1 -> SCLK (DOPO 0)
182 * PA06 SERCOM0.2 -> MISO (DIPO 2)
184 #define AO_SPI_0_PA04_PA05_PA06 (0 | AO_SPI_CONFIG_1 | \
185 AO_SPI_DOPO_MOSI_0_SCLK_1 | \
187 #endif /* HAS_SPI_0 */
191 * PA22 SERCOM3.0 -> MOSI (DOPO 0)
192 * PA23 SERCOM3.1 -> SCLK (DOPO 0)
193 * PA20 SERCOM3.2 -> MISO (DIPO 2)
195 #define AO_SPI_3_PA22_PA23_PA20 (3 | AO_SPI_CONFIG_0 | \
196 AO_SPI_DOPO_MOSI_0_SCLK_1 | \
198 #endif /* HAS_SPI_3 */
202 * PA04 SERCOM0.0 -> MOSI (DOPO 0)
203 * PA05 SERCOM0.1 -> SCLK (DOPO 0)
204 * PA16 SERCOM0.2 -> MISO (DIPO 2)
206 #define AO_SPI_CONFIG_PA04_PA05_PA06 (0 | AO_SPI_CONFIG_1 | \
207 AO_SPI_DOPO_MOSI_0_SCLK_1 | \
211 * PB10 SERCOM4.2 -> MOSI (DOPO 1)
212 * PB11 SERCOM4.3 -> SCLK (DOPO 1)
213 * PA12 SERCOM4.0 -> MISO (DIPO 0)
215 #define AO_SPI_4_PB10_PB11_PA12 (4 | AO_SPI_CONFIG_0 | \
216 AO_SPI_DOPO_MOSI_2_SCLK_3 | \
218 #endif /* HAS_SPI_4 */
222 * PB22 SERCOM5.2 -> MOSI (DOPO 1)
223 * PB23 SERCOM5.3 -> SCLK (DOPO 1)
224 * PB03 SERCOM5.1 -> MISO (DIPO 1)
226 #define AO_SPI_5_PB22_PB23_PB03 (5 | AO_SPI_CONFIG_0 | \
227 AO_SPI_DOPO_MOSI_2_SCLK_3 | \
229 #endif /* HAS_SPI_5 */
232 ao_spi_send(const void *block, uint16_t len, uint16_t spi_index);
235 ao_spi_send_fixed(uint8_t data, uint16_t len, uint16_t spi_index);
238 ao_spi_recv(void *block, uint16_t len, uint16_t spi_index);
241 ao_spi_duplex(const void *out, void *in, uint16_t len, uint16_t spi_index);
244 ao_spi_get(uint16_t spi_index, uint32_t speed);
247 ao_spi_put(uint16_t spi_index);
252 #define ao_spi_set_cs(reg,mask) do { \
253 reg->outclr = mask; \
256 #define ao_spi_clr_cs(reg,mask) do { \
257 reg->outset = mask; \
260 #define ao_spi_get_mask(reg,mask,spi_index, speed) do { \
261 ao_spi_get(spi_index, speed); \
262 ao_spi_set_cs(reg,mask); \
265 #define ao_spi_put_mask(reg,mask,spi_index) do { \
266 ao_spi_clr_cs(reg,mask); \
267 ao_spi_put(spi_index); \
271 ao_spi_get_bit(struct samd21_port *port, uint8_t bit, uint16_t spi_index, uint32_t speed)
273 ao_spi_get(spi_index, speed);
274 ao_gpio_set(port, bit, 0);
278 ao_spi_put_bit(struct samd21_port *port, uint8_t bit, uint16_t spi_index)
280 ao_gpio_set(port, bit, 1);
281 ao_spi_put(spi_index);
284 static inline uint8_t
285 ao_spi_speed(int index, uint32_t hz)
287 int32_t baud = (int32_t) (AO_SYSCLK / (2 * hz)) - 1;
294 return (uint8_t) baud;
297 #define ao_spi_init_cs(port, mask) do { \
299 for (__bit__ = 0; __bit__ < 32; __bit__++) { \
300 if (mask & (1 << __bit__)) \
301 ao_enable_output(port, __bit__, 1); \
305 #define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
307 typedef uint32_t ao_arch_irq_t;
309 static inline uint32_t
310 ao_arch_irqsave(void) {
312 asm("mrs %0,primask" : "=&r" (primask));
313 ao_arch_block_interrupts();
318 ao_arch_irqrestore(uint32_t primask) {
319 asm("msr primask,%0" : : "r" (primask));
323 ao_arch_memory_barrier(void) {
324 asm volatile("" ::: "memory");
329 ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
331 uint32_t a = (uint32_t) start;
334 /* Return address (goes into LR) */
337 /* Clear register values r0-r7 */
345 /* PRIMASK with interrupts enabled */
351 static inline void ao_arch_save_regs(void) {
352 /* Save general registers */
353 asm("push {r0-r7,lr}\n");
360 asm("mrs r0,primask");
364 static inline void ao_arch_save_stack(void) {
366 asm("mov %0,sp" : "=&r" (sp) );
367 ao_cur_task->sp32 = (sp);
368 if (sp < &ao_cur_task->stack32[0])
369 ao_panic (AO_PANIC_STACK);
372 static inline void ao_arch_restore_stack(void) {
374 asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
376 /* Restore PRIMASK */
378 asm("msr primask,r0");
382 asm("msr apsr_nczvq,r0");
384 /* Restore general registers */
385 asm("pop {r0-r7,pc}\n");
388 #ifndef HAS_SAMPLE_PROFILE
389 #define HAS_SAMPLE_PROFILE 0
392 #if !HAS_SAMPLE_PROFILE
393 #define HAS_ARCH_START_SCHEDULER 1
395 static inline void ao_arch_start_scheduler(void) {
399 asm("mrs %0,msp" : "=&r" (sp));
400 asm("msr psp,%0" : : "r" (sp));
401 asm("mrs %0,control" : "=&r" (control));
403 asm("msr control,%0" : : "r" (control));
408 #define ao_arch_isr_stack()
412 #define ao_arch_wait_interrupt() do { \
414 ao_arch_release_interrupts(); \
415 asm(".global ao_idle_loc\nao_idle_loc:"); \
416 ao_arch_block_interrupts(); \
419 #define ao_arch_critical(b) do { \
420 uint32_t __mask = ao_arch_irqsave(); \
421 do { b } while (0); \
422 ao_arch_irqrestore(__mask); \
425 /* ao_serial_samd21.c */
427 #if USE_SERIAL_0_FLOW && USE_SERIAL_0_SW_FLOW || USE_SERIAL_1_FLOW && USE_SERIAL_1_SW_FLOW
428 #define HAS_SERIAL_SW_FLOW 1
430 #define HAS_SERIAL_SW_FLOW 0
433 #if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW
434 #define USE_SERIAL_1_HW_FLOW 1
437 #if USE_SERIAL_0_FLOW && !USE_SERIAL_0_SW_FLOW
438 #define USE_SERIAL_0_HW_FLOW 1
441 #if USE_SERIAL_0_HW_FLOW || USE_SERIAL_1_HW_FLOW
442 #define HAS_SERIAL_HW_FLOW 1
444 #define HAS_SERIAL_HW_FLOW 0
447 struct ao_samd21_usart {
448 struct ao_fifo rx_fifo;
449 struct ao_fifo tx_fifo;
450 struct samd21_sercom *reg;
453 #if HAS_SERIAL_SW_FLOW
454 /* RTS - 0 if we have FIFO space, 1 if not
455 * CTS - 0 if we can send, 0 if not
457 struct samd21_port *gpio_rts;
458 struct samd21_port *gpio_cts;
466 extern struct ao_samd21_usart ao_samd21_usart0;
470 ao_serial_init(void);
472 /* ao_usb_samd21.c */
476 ao_usb_out_hook(uint8_t *buffer, uint16_t count);
481 #endif /* _AO_ARCH_FUNCS_H_ */