/* * 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; either version 2 of the License, or * (at your option) any later version. * * 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_ #include /* ao_spi_stm.c */ /* PCLK is set to 48MHz (HCLK 48MHz, HPRE 1, PPRE 1) */ #define AO_SPI_SPEED_24MHz STM_SPI_CR1_BR_PCLK_2 #define AO_SPI_SPEED_12MHz STM_SPI_CR1_BR_PCLK_4 #define AO_SPI_SPEED_6MHz STM_SPI_CR1_BR_PCLK_8 #define AO_SPI_SPEED_3MHz STM_SPI_CR1_BR_PCLK_16 #define AO_SPI_SPEED_1500kHz STM_SPI_CR1_BR_PCLK_32 #define AO_SPI_SPEED_750kHz STM_SPI_CR1_BR_PCLK_64 #define AO_SPI_SPEED_375kHz STM_SPI_CR1_BR_PCLK_128 #define AO_SPI_SPEED_187500Hz STM_SPI_CR1_BR_PCLK_256 #define AO_SPI_SPEED_FAST AO_SPI_SPEED_24MHz /* Companion bus wants something no faster than 200kHz */ #define AO_SPI_SPEED_200kHz AO_SPI_SPEED_187500Hz #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(const void *block, uint16_t len, uint8_t spi_index); void ao_spi_start_bytes(uint8_t spi_index); void ao_spi_stop_bytes(uint8_t spi_index); static inline void ao_spi_send_byte(uint8_t byte, uint8_t spi_index) { struct stm_spi *stm_spi; switch (AO_SPI_INDEX(spi_index)) { case 0: stm_spi = &stm_spi1; break; case 1: stm_spi = &stm_spi2; break; } while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE))) ; stm_spi->dr = byte; while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE))) ; (void) stm_spi->dr; } static inline uint8_t ao_spi_recv_byte(uint8_t spi_index) { struct stm_spi *stm_spi; switch (AO_SPI_INDEX(spi_index)) { case 0: stm_spi = &stm_spi1; break; case 1: stm_spi = &stm_spi2; break; } while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE))) ; stm_spi->dr = 0xff; while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE))) ; return stm_spi->dr; } 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-r7 */ i = 8; 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-r7,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-r7,pc}\n"); } #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) /* ao_usb_stm.c */ #if AO_USB_DIRECTIO uint16_t * ao_usb_alloc(void); void ao_usb_write(uint16_t *buffer, uint16_t len); void ao_usb_write2(uint16_t *buffer, uint16_t len); #endif /* AO_USB_DIRECTIO */ #endif /* _AO_ARCH_FUNCS_H_ */