aboutsummaryrefslogtreecommitdiff
path: root/02-usart/src/kern/dma/dma_manager.c
diff options
context:
space:
mode:
Diffstat (limited to '02-usart/src/kern/dma/dma_manager.c')
-rw-r--r--02-usart/src/kern/dma/dma_manager.c311
1 files changed, 0 insertions, 311 deletions
diff --git a/02-usart/src/kern/dma/dma_manager.c b/02-usart/src/kern/dma/dma_manager.c
deleted file mode 100644
index 00e9f3d..0000000
--- a/02-usart/src/kern/dma/dma_manager.c
+++ /dev/null
@@ -1,311 +0,0 @@
-#include "kern/dma/dma_manager.h"
-#include "arch/stm32l4xxx/peripherals/dma.h"
-#include "arch/stm32l4xxx/peripherals/usart.h"
-#include "arch/stm32l4xxx/peripherals/rcc.h"
-
-
-/* Bitmask of DMA2 channels in use. */
-static uint8_t dma_inuse[2];
-
-static inline dma_t* get_dma(int dma)
-{
- if (dma) {
- return &DMA2;
- } else {
- return &DMA1;
- }
-}
-
-static dma_t* get_raw_dma(dma_channel_t chan)
-{
- return get_dma(chan.dma);
-}
-
-static dma_channel_config_t* get_raw_channel_config(dma_channel_t chan)
-{
- dma_t* dma = get_raw_dma(chan);
- return &dma->channel_config[chan.chan];
-}
-
-static uint32_t get_periph_location(dma_peripheral_t operipheral)
-{
-#define CASE(p, n) case p: return ptr2reg(n);
- switch (operipheral) {
- CASE(DMA1_PERIPH_USART1_RX, &USART1.rd_r)
- CASE(DMA1_PERIPH_USART1_TX, &USART1.td_r)
- CASE(DMA1_PERIPH_USART2_RX, &USART2.rd_r)
- CASE(DMA1_PERIPH_USART2_TX, &USART2.td_r)
-
- default:
- return 0;
- };
-#undef CASE
-}
-
-static dma_channel_t allocate_dma_channel(
- dma_peripheral_t operipheral, int* modesel)
-{
- dma_peripheral_t peripheral = operipheral & 0xff;
- int dmasel = peripheral >= DMA2_DMA1_SWITCH__;
- if (dmasel) {
- peripheral -= DMA2_DMA1_SWITCH__;
- }
- int chan = peripheral % DMA_N_CHANNELS;
-
- *modesel = peripheral / 7;
- return (dma_channel_t) {
- .dma = dmasel,
- .chan = chan
- };
-}
-
-/*
- * Atomically reserves the DMA channel so other calls
- * cannot erroneously reserve the same DMA channel.
- *
- * Returns 0 if this function was unable to reserve
- * the channel.
- */
-static int try_reserve_dma_channel(
- dma_channel_t chan)
-{
- int in_use = __sync_fetch_and_or(
- &dma_inuse[chan.dma], 1 << chan.chan);
-
- return !(in_use & (1 << chan.chan));
-}
-
-void release_dma_channel(dma_channel_t chan)
-{
- dma_channel_config_t* config = get_raw_channel_config(chan);
- regset(config->cc_r, dma_cc_en, 0); /* Disable the register. */
- dma_inuse[chan.dma] &= ~(1 << chan.chan); /* Release the DMA. */
-
- if (!dma_inuse[chan.dma]) {
- /* Power-down the DMA if not in use. */
- if (chan.dma) {
- regset(RCC.ahb1en_r, rcc_dma2en, 0);
- } else {
- regset(RCC.ahb1en_r, rcc_dma1en, 0);
- }
- }
-}
-
-void configure_dma_channel(
- dma_channel_t chan,
- dma_peripheral_t operipheral,
- dma_opts_t* opts,
- dma_dir_t dir,
- int selmode,
- bool mem2mem,
- int* error_out)
-{
- if (chan.dma) {
- regset(RCC.ahb1en_r, rcc_dma2en, 1);
- } else {
- regset(RCC.ahb1en_r, rcc_dma1en, 1);
- }
-
- dma_t* dma = get_raw_dma(chan);
- regset(dma->csel_r, 0xF << (4 * chan.chan), selmode);
- dma_channel_config_t* config =
- &dma->channel_config[chan.chan];
-
- uint32_t reg = 0;
-
- regset(reg, dma_cc_dir, dir);
- regset(reg, dma_cc_tcie, opts->transfer_complete_interrupt_enable);
- regset(reg, dma_cc_htie, opts->half_transfer_interrupt_enable);
- regset(reg, dma_cc_teie, opts->transfer_error_interrupt_enable);
- regset(reg, dma_cc_circ, opts->circular_mode);
- regset(reg, dma_cc_pinc, opts->peripheral_increment);
- regset(reg, dma_cc_minc, opts->memory_increment);
- regset(reg, dma_cc_psize, opts->peripheral_block_size);
- regset(reg, dma_cc_msize, opts->memory_block_size);
- regset(reg, dma_cc_pl, opts->priority);
- regset(reg, dma_cc_mem2mem, mem2mem);
-
- config->cc_r = reg;
- config->cpa_r = get_periph_location(operipheral);
-
- *error_out = 0;
-}
-
-dma_mem2mem_channel_t select_dma_channel_mem2mem(
- int channel,
- dma_opts_t* opts,
- int* error_out)
-{
-
-#define WRAP(c) ((dma_mem2mem_channel_t) { .c_ = c })
- // TODO this should probably be in a critical section.
- dma_channel_t chan;
- if (channel == -1) {
- chan.dma = 1;
- if ((dma_inuse[chan.dma] & 0x7F) == 0x7F) {
- chan.dma = 0;
- }
-
- if ((dma_inuse[chan.dma] & 0x7F) == 0x7F) {
- *error_out = DMA_ERROR_CHANNEL_IN_USE;
- return WRAP(DMA_CHAN_ERROR);
- }
-
- uint8_t t = ~(dma_inuse[chan.dma] << 1);
- chan.chan = 6 - (__builtin_clz(t) - 24);
- } else {
- if (channel < 7) {
- chan.dma = 0;
- chan.chan = channel;
- } else {
- chan.dma = 0;
- chan.chan = channel - 7;
- }
- }
-
- if (!try_reserve_dma_channel(chan)) {
- *error_out = DMA_ERROR_CHANNEL_IN_USE;
- return WRAP(DMA_CHAN_ERROR);
- }
-
- int ec = 0;
- configure_dma_channel(
- chan,
- -1 /* No peripheral */,
- opts,
- READ_FROM_PERIPHERAL,
- /* selmode = */ 0x8,
- /* mem2mem = */ true,
- &ec);
-
- if (ec) {
- *error_out = ec;
- return WRAP(DMA_CHAN_ERROR);
- }
-
- *error_out = 0;
- return WRAP(chan);
-#undef WRAP
-}
-
-dma_mem2p_channel_t select_dma_channel_mem2p(
- dma_peripheral_t peripheral,
- dma_opts_t* opts_in,
- int* error_out)
-{
-#define WRAP(c) ((dma_mem2p_channel_t) { .c_ = c })
- *error_out = 0;
-
- int modesel;
- dma_channel_t ret =
- allocate_dma_channel(peripheral, &modesel);
-
- if (!try_reserve_dma_channel(ret)) {
- *error_out = DMA_ERROR_CHANNEL_IN_USE;
- return WRAP(DMA_CHAN_ERROR);
- }
-
- configure_dma_channel(
- ret,
- peripheral,
- opts_in,
- READ_FROM_MEMORY,
- modesel,
- /* mem2mem = */ false,
- error_out);
-
- if (*error_out) {
- return WRAP(DMA_CHAN_ERROR);
- }
-
- *error_out = 0;
- return WRAP(ret);
-#undef WRAP
-}
-
-dma_p2mem_channel_t select_dma_channel_p2mem(
- dma_peripheral_t peripheral,
- dma_opts_t* opts_in,
- int* error_out)
-{
-#define WRAP(c) ((dma_p2mem_channel_t) { .c_ = c })
- *error_out = 0;
-
- int modesel;
- dma_channel_t ret =
- allocate_dma_channel(peripheral, &modesel);
-
- if (!try_reserve_dma_channel(ret)) {
- *error_out = DMA_ERROR_CHANNEL_IN_USE;
- return WRAP(DMA_CHAN_ERROR);
- }
-
- configure_dma_channel(
- ret,
- peripheral,
- opts_in,
- READ_FROM_PERIPHERAL,
- modesel,
- /* mem2mem = */ false,
- error_out);
-
- if (*error_out) {
- return WRAP(DMA_CHAN_ERROR);
- }
-
- *error_out = 0;
- return WRAP(ret);
-#undef WRAP
-}
-
-
-void dma_mem2p_initiate_transfer(
- dma_mem2p_channel_t chan, const void* from_loc, uint16_t nblocks)
-{
- dma_channel_config_t* config = get_raw_channel_config(chan.c_);
- config->cma_r = ptr2reg(from_loc);
- config->cndt_r = nblocks;
-
- regset(config->cc_r, dma_cc_en, 1);
-}
-
-void dma_mem2mem_initiate_transfer(
- dma_mem2mem_channel_t chan,
- void* to_loc,
- const void* from_loc,
- uint16_t nblocks)
-{
- dma_channel_config_t* config = get_raw_channel_config(chan.c_);
- config->cma_r = ptr2reg(to_loc);
- config->cpa_r = ptr2reg(from_loc);
- config->cndt_r = nblocks;
-
- regset(config->cc_r, dma_cc_en, 1);
-}
-
-void dma_p2mem_initiate_transfer(
- dma_p2mem_channel_t chan, void* to_loc, uint16_t nblocks)
-{
- dma_channel_config_t* config = get_raw_channel_config(chan.c_);
-
- config->cma_r = ptr2reg(to_loc);
- config->cndt_r = nblocks;
-
- regset(config->cc_r, dma_cc_en, 1);
-}
-
-interrupt_t dma_channel_get_interrupt(dma_channel_t chan)
-{
- if (chan.dma == 0) {
- return IRQ_DMA1_CHANNEL1_IRQ + chan.chan;
- } else {
- switch (chan.chan) {
- case 5:
- return IRQ_DMA1_CHANNEL6_IRQ;
- case 6:
- return IRQ_DMA1_CHANNEL7_IRQ;
- default:
- return IRQ_DMA2_CHANNEL1_IRQ + chan.chan;
- }
- }
-}