diff options
Diffstat (limited to 'include/kern/dma/dma_manager.h')
-rw-r--r-- | include/kern/dma/dma_manager.h | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/include/kern/dma/dma_manager.h b/include/kern/dma/dma_manager.h new file mode 100644 index 0000000..0d17bd5 --- /dev/null +++ b/include/kern/dma/dma_manager.h @@ -0,0 +1,279 @@ +#ifndef PERI_DMA_H_ +#define PERI_DMA_H_ + +#include "kern/common.h" +#include "arch/stm32l4xxx/peripherals/dma.h" /* Access to the DMA registers. */ +#include "arch/stm32l4xxx/peripherals/irq.h" + +#define DMA_ERROR_CHANNEL_IN_USE 1 + +#define CAT2(x, y) x ## y +#define CAT1(v, c) CAT2(v, c) +#define DMA_RESERVED(dma) CAT1(dma ## _PERIPH_RESERVED, __COUNTER__) + +#define ALTERNATE0 0x0000 +#define ALTERNATE1 0x0100 +#define ALTERNATE2 0x0200 +#define ALTERNATE3 0x0300 + +#define DMA_N_CHANNELS 7 +typedef enum { + DMA1_PERIPH_ADC1 = 0, + DMA1_PERIPH_ADC2 = 1, + DMA1_PERIPH_ADC3 = 2, + DMA1_PERIPH_DFSDM1_FLT0 = 3, + DMA1_PERIPH_DFSDM1_FLT1 = 4, + DMA1_PERIPH_DFSDM1_FLT2 = 5, + DMA1_PERIPH_DFSDM1_FLT3 = 6, + + DMA_RESERVED(DMA1) = 7, + DMA1_PERIPH_SPI1_RX = 8, + DMA1_PERIPH_SPI1_TX = 9, + DMA1_PERIPH_SPI2_RX = 10, + DMA1_PERIPH_SPI2_TX = 11, + DMA1_PERIPH_SAI2_A = 12, + DMA1_PERIPH_SAI2_B = 13, + + DMA_RESERVED(DMA1) = 14, + DMA1_PERIPH_USART3_TX = 15, + DMA1_PERIPH_USART3_RX = 16, + DMA1_PERIPH_USART1_TX = 17, + DMA1_PERIPH_USART1_RX = 18, + DMA1_PERIPH_USART2_RX = 19, + DMA1_PERIPH_USART2_TX = 20, + + DMA_RESERVED(DMA1) = 21, + DMA1_PERIPH_I2C3_TX = 22, + DMA1_PERIPH_I2C3_RX = 23, + DMA1_PERIPH_I2C2_TX = 24, + DMA1_PERIPH_I2C2_RX = 25, + DMA1_PERIPH_I2C1_TX = 26, + DMA1_PERIPH_I2C1_RX = 27, + + DMA1_PERIPH_TIM2_CH3 = 28, + DMA1_PERIPH_TIM2_UP = 29, + DMA1_PERIPH_TIM16_CH1_1 = 30 | ALTERNATE0, + DMA1_PERIPH_TIM16_UP_1 = 30 | ALTERNATE1, /* Same as TIM16_CH1. */ + DMA_RESERVED(DMA1) = 31, + DMA1_PERIPH_TIM2_CH1 = 32, + DMA1_PERIPH_TIM16_CH1_2 = 33, + DMA1_PERIPH_TIM16_UP_2 = 33 | ALTERNATE1, /* Same as TIM16_CH1. */ + DMA1_PERIPH_TIM2_CH2 = 34, + DMA1_PERIPH_TIM2_CH4 = 34 | ALTERNATE1, /* Same as TIM2_CH2. */ + + + DMA1_PERIPH_TIM17_CH1_1 = 35, + DMA1_PERIPH_TIM17_UP_1 = 35 | ALTERNATE1, /* Same as TIM17_CH1 */ + DMA1_PERIPH_TIM3_CH3 = 36, + DMA1_PERIPH_TIM3_CH4 = 37, + DMA1_PERIPH_TIM3_UP = 37 | ALTERNATE1, /* Same as TIM3_CH4 */ + DMA1_PERIPH_TIM7_UP = 38, + DMA1_PERIPH_DAC_CH2 = 38 | ALTERNATE1, /* Same as TIM7_UP */ + DMA1_PERIPH_QUADSPI = 39, + DMA1_PERIPH_TIM3_CH1 = 40, + DMA1_PERIPH_TIM3_TRIG = 40 | ALTERNATE1, /* Same as TIM3_CH1 */ + DMA1_PERIPH_TIM17_CH1_2 = 41, + DMA1_PERIPH_TIM17_UP_2 = 41 | ALTERNATE1, /* Same as TIM17_CH1 */ + + DMA1_PERIPH_TIM4_CH1 = 42, + DMA_RESERVED(DMA1) = 43, + DMA1_PERIPH_TIM6_UP = 44, + DMA1_PERIPH_DAC_CH1 = 44 | ALTERNATE1, /* Same as TIM6_UP */ + DMA1_PERIPH_TIM4_CH2 = 45, + DMA1_PERIPH_TIM4_CH3 = 46, + DMA_RESERVED(DMA1) = 47, + DMA1_PERIPH_TIM4_UP = 48, + + DMA_DMA1_PERIHP_RESERVED5 = 49, + DMA1_PERIPH_TIM1_CH1 = 50, + DMA1_PERIPH_TIM1_CH2 = 51, + DMA1_PERIPH_TIM1_CH4 = 52, + DMA1_PERIPH_TIM1_TRIG = 52 | ALTERNATE1, /* Same as TIM1_TRIG */ + DMA1_PERIPH_TIM1_COM = 52 | ALTERNATE2, /* Same as TIM1_TRIG */ + DMA1_PERIPH_TIM15_CH1 = 53, + DMA1_PERIPH_TIM15_UP = 53 | ALTERNATE1, /* Same as TIM15_CH1 */ + DMA1_PERIPH_TIM15_TRIG = 53 | ALTERNATE2, /* Same as TIM15_CH1 */ + DMA1_PERIPH_TIM15_COM = 53 | ALTERNATE3, /* Same as TIM15_CH1 */ + DMA1_PERIPH_TIM1_UP = 54, + DMA1_PERIPH_TIM1_CH3 = 55, + + DMA2_DMA1_SWITCH__ = 56, + + DMA2_PERIPH_I2C4_RX = 56, + DMA2_PERIPH_I2C4_TX = 57, + DMA2_PERIPH_ADC1 = 58, + DMA2_PERIPH_ADC2 = 59, + DMA2_PERIPH_ADC3 = 60, + DMA2_PERIPH_DCMI_1 = 61, + DMA_RESERVED(DMA2) = 62, + + DMA2_PERIPH_SAI1_A_1 = 63, + DMA2_PERIPH_SAI1_B_1 = 64, + DMA2_PERIPH_SAI2_A = 65, + DMA2_PERIPH_SAI2_B = 66, + DMA_RESERVED(DMA2) = 67, + DMA2_PERIPH_SAI1_A_2 = 68, + DMA2_PERIPH_SAI1_B_2 = 69, + + DMA2_PERIPH_UART5_TX = 70, + DMA2_PERIPH_UART5_RX = 71, + DMA2_PERIPH_UART4_TX = 72, + DMA_RESERVED(DMA2) = 73, + DMA2_PERIPH_UART4_RX = 74, + DMA2_PERIPH_USART1_TX = 75, + DMA2_PERIPH_USART1_RX = 76, + + DMA2_PERIPH_SPI3_RX = 77, + DMA2_PERIPH_SPI3_TX = 78, + DMA_RESERVED(DMA2) = 79, + DMA2_PERIPH_TIM6_UP = 80, + DMA2_PERIPH_DAC_CH1 = 80 | ALTERNATE1, /* Same as TIM6_UP */ + DMA2_PERIPH_TIM7_UP = 81, + DMA2_PERIPH_DAC_CH2 = 81 | ALTERNATE1, /* Same as TIM7_UP */ + DMA_RESERVED(DMA2) = 82, + DMA2_PERIPH_QUADSPI = 83, + + DMA2_PERIPH_SWPMI1_RX = 84, + DMA2_PERIPH_SWPMI1_TX = 85, + DMA2_PERIPH_SPI1_RX = 86, + DMA2_PERIPH_SPI1_TX = 87, + DMA2_PERIPH_DCMI_2 = 88, + DMA2_PERIPH_LPUART1_TX = 89, + DMA2_PERIPH_LPUART1_RX = 90, + + + DMA2_PERIPH_TIM5_CH4 = 91, + DMA2_PERIPH_TIM5_TRIG = 91 | ALTERNATE1, /* Same as TIM5_CH4 */ + DMA2_PERIPH_TIM5_CH3 = 92, + DMA2_PERIPH_TIM5_UP = 92 | ALTERNATE1, /* Same as TIM5_CH3 */ + DMA_RESERVED(DMA2) = 93, + DMA2_PERIPH_TIM5_CH2 = 94, + DMA2_PERIPH_TIM5_CH1 = 95, + DMA2_PERIPH_I2C1_RX = 96, + DMA2_PERIPH_I2C1_TX = 97, + + DMA2_PERIPH_AES_IN_1 = 98, + DMA2_PERIPH_AES_OUT_1 = 99, + DMA2_PERIPH_AES_OUT_2 = 100, + DMA_RESERVED(DMA2) = 101, + DMA2_PERIPH_AES_IN_2 = 102, + DMA_RESERVED(DMA2) = 103, + DMA2_PERIPH_HASH_IN = 104, + + DMA2_PERIPH_TIM8_CH3 = 105, + DMA2_PERIPH_TIM8_UP = 105 | ALTERNATE1, /* Same as TIM8_CH3 */ + DMA2_PERIPH_TIM8_CH4 = 106, + DMA2_PERIPH_TIM8_TRIG = 106 | ALTERNATE1, /* Same as TIM8_CH4 */ + DMA2_PERIPH_TIM8_COM = 106 | ALTERNATE2, /* Same as TIM8_CH4 */ + DMA_RESERVED(DMA2) = 107, + DMA2_PERIPH_SDMMC1_1 = 108, + DMA2_PERIPH_SDMMC1_2 = 109, + DMA2_PERIPH_TIM8_CH1 = 110, + DMA2_PERIPH_TIM8_CH2 = 111, + + + DMA_PERIPH_SENTINEL, +} dma_peripheral_t; + + +/* Defines a DMA channel. */ +typedef struct { + uint8_t dma; /* 0 = DMA1, 1 = DMA2 */ + uint8_t chan; /* 0 - 6 */ +} dma_channel_t; + + +/* + * Defines a DMA channel allocated for memory-to-peripheral transfers. This + * structure is only nominally different from dma_channel_t in order to provide + * rudimentary type-checking. + */ +typedef struct { + dma_channel_t c_; +} dma_mem2p_channel_t; + +/* + * Defines a DMA channel allocated for peripheral-to-memory transfers. This + * structure is only nominally different from dma_channel_t in order to provide + * rudimentary type-checking. + */ +typedef struct { + dma_channel_t c_; +} dma_p2mem_channel_t; + +/* Defines a DMA channel allocated for mem2mem transfers. + * This structure is only nominally different from dma_channel_t + * in order to provide rudimentary type-checking. + */ +typedef struct { + dma_channel_t c_; +} dma_mem2mem_channel_t; + +#define DMA_CHAN_ERROR ((dma_channel_t) { .dma = 0xff, .chan = 0xff }) + +typedef struct { + bool transfer_complete_interrupt_enable; + bool half_transfer_interrupt_enable; + bool transfer_error_interrupt_enable; + + bool circular_mode; + bool peripheral_increment; + bool memory_increment; + + dma_size_t peripheral_block_size; + dma_size_t memory_block_size; + + dma_priority_level_t priority; +} dma_opts_t; + +#define DEFAULT_DMA_OPTS \ + ((dma_opts_t) { .memory_increment = 1, \ + .peripheral_increment = 0, \ + .transfer_complete_interrupt_enable = 0, \ + .half_transfer_interrupt_enable = 0, \ + .transfer_error_interrupt_enable = 0, \ + .circular_mode = 0, \ + .peripheral_block_size = DMA_SIZE_8_BITS, \ + .memory_block_size = DMA_SIZE_8_BITS, \ + .priority = DMA_PRIORITY_LEVEL_MEDIUM }) + +dma_p2mem_channel_t select_dma_channel_p2mem( + dma_peripheral_t peripheral, + dma_opts_t* opts_in, + int* error); + +dma_mem2p_channel_t select_dma_channel_mem2p( + dma_peripheral_t peripheral, + dma_opts_t* opts_in, + int* error); + +/* Returns a dma channel used for memory-to-memory transfers. + * + * channel - the channel this dma should use. The channel should + * be on the range [0-13]. The channels [0-6] refer to the 7 channels + * on DMA1, where channels [7-13] refer to the 7 channels on DMA2. + * + * If `channel` is -1, then the highest unused dma channel is selected. + */ +dma_mem2mem_channel_t select_dma_channel_mem2mem( + int channel, + dma_opts_t* opts, + int* error_out); + +void dma_mem2p_initiate_transfer( + dma_mem2p_channel_t chan, const void* from_loc, uint16_t nblocks); + +void dma_p2mem_initiate_transfer( + dma_p2mem_channel_t chan, void* to_loc, uint16_t nblocks); + +void dma_mem2mem_initiate_transfer( + dma_mem2mem_channel_t chan, + void* to_loc, + const void* from_loc, + uint16_t nblocks); + +void release_dma_channel(dma_channel_t chan); + +interrupt_t dma_channel_get_interrupt(dma_channel_t chan); + +#endif |