/* * Copyright © 2012 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _AO_ARCH_FUNCS_H_ #define _AO_ARCH_FUNCS_H_ /* ao_spi_stm.c */ /* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */ #define AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2 #define AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4 #define AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8 #define AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16 #define AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32 #define AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64 #define AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128 #define AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256 #define AO_SPI_SPEED_FAST AO_SPI_SPEED_8MHz /* Companion bus wants something no faster than 200kHz */ #define AO_SPI_SPEED_200kHz AO_SPI_SPEED_125kHz #define AO_SPI_CONFIG_1 0x00 #define AO_SPI_1_CONFIG_PA5_PA6_PA7 AO_SPI_CONFIG_1 #define AO_SPI_2_CONFIG_PB13_PB14_PB15 AO_SPI_CONFIG_1 #define AO_SPI_CONFIG_2 0x04 #define AO_SPI_1_CONFIG_PB3_PB4_PB5 AO_SPI_CONFIG_2 #define AO_SPI_2_CONFIG_PD1_PD3_PD4 AO_SPI_CONFIG_2 #define AO_SPI_CONFIG_3 0x08 #define AO_SPI_1_CONFIG_PE13_PE14_PE15 AO_SPI_CONFIG_3 #define AO_SPI_CONFIG_NONE 0x0c #define AO_SPI_INDEX_MASK 0x01 #define AO_SPI_CONFIG_MASK 0x0c #define AO_SPI_1_PA5_PA6_PA7 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PA5_PA6_PA7) #define AO_SPI_1_PB3_PB4_PB5 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PB3_PB4_PB5) #define AO_SPI_1_PE13_PE14_PE15 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PE13_PE14_PE15) #define AO_SPI_2_PB13_PB14_PB15 (STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PB13_PB14_PB15) #define AO_SPI_2_PD1_PD3_PD4 (STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PD1_PD3_PD4) #define AO_SPI_INDEX(id) ((id) & AO_SPI_INDEX_MASK) #define AO_SPI_CONFIG(id) ((id) & AO_SPI_CONFIG_MASK) uint8_t ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id); void ao_spi_get(uint8_t spi_index, uint32_t speed); void ao_spi_put(uint8_t spi_index); void ao_spi_send(const void *block, uint16_t len, uint8_t spi_index); void ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index); void ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index); void ao_spi_recv(void *block, uint16_t len, uint8_t spi_index); void ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index); extern uint16_t ao_spi_speed[STM_NUM_SPI]; void ao_spi_init(void); #define ao_spi_set_cs(reg,mask) ((reg)->bsrr = ((uint32_t) (mask)) << 16) #define ao_spi_clr_cs(reg,mask) ((reg)->bsrr = (mask)) #define ao_spi_get_mask(reg,mask,bus, speed) do { \ ao_spi_get(bus, speed); \ ao_spi_set_cs(reg,mask); \ } while (0) static inline uint8_t ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t speed, uint8_t task_id) { if (!ao_spi_try_get(bus, speed, task_id)) return 0; ao_spi_set_cs(reg, mask); return 1; } #define ao_spi_put_mask(reg,mask,bus) do { \ ao_spi_clr_cs(reg,mask); \ ao_spi_put(bus); \ } while (0) #define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<stack + AO_STACK_SIZE); uint32_t a = (uint32_t) start; int i; /* Return address (goes into LR) */ ARM_PUSH32(sp, a); /* Clear register values r0-r12 */ i = 13; while (i--) ARM_PUSH32(sp, 0); /* APSR */ ARM_PUSH32(sp, 0); /* PRIMASK with interrupts enabled */ ARM_PUSH32(sp, 0); task->sp = sp; } static inline void ao_arch_save_regs(void) { /* Save general registers */ asm("push {r0-r12,lr}\n"); /* Save APSR */ asm("mrs r0,apsr"); asm("push {r0}"); /* Save PRIMASK */ asm("mrs r0,primask"); asm("push {r0}"); } static inline void ao_arch_save_stack(void) { uint32_t *sp; asm("mov %0,sp" : "=&r" (sp) ); ao_cur_task->sp = (sp); if ((uint8_t *) sp < &ao_cur_task->stack[0]) ao_panic (AO_PANIC_STACK); } static inline void ao_arch_restore_stack(void) { uint32_t sp; sp = (uint32_t) ao_cur_task->sp; /* Switch stacks */ asm("mov sp, %0" : : "r" (sp) ); /* Restore PRIMASK */ asm("pop {r0}"); asm("msr primask,r0"); /* Restore APSR */ asm("pop {r0}"); asm("msr apsr_nczvq,r0"); /* Restore general registers */ asm("pop {r0-r12,lr}\n"); /* Return to calling function */ asm("bx lr"); } #ifndef HAS_SAMPLE_PROFILE #define HAS_SAMPLE_PROFILE 0 #endif #if !HAS_SAMPLE_PROFILE #define HAS_ARCH_START_SCHEDULER 1 static inline void ao_arch_start_scheduler(void) { uint32_t sp; uint32_t control; asm("mrs %0,msp" : "=&r" (sp)); asm("msr psp,%0" : : "r" (sp)); asm("mrs %0,control" : "=&r" (control)); control |= (1 << 1); asm("msr control,%0" : : "r" (control)); asm("isb"); } #endif #define ao_arch_isr_stack() #endif #define ao_arch_wait_interrupt() do { \ asm("\twfi\n"); \ ao_arch_release_interrupts(); \ asm(".global ao_idle_loc\nao_idle_loc:"); \ ao_arch_block_interrupts(); \ } while (0) #define ao_arch_critical(b) do { \ uint32_t __mask = ao_arch_irqsave(); \ do { b } while (0); \ ao_arch_irqrestore(__mask); \ } while (0) #endif /* _AO_ARCH_FUNCS_H_ */