1 /*
2 * Copyright (c) 2016 Erik Gilling
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <platform/dma.h>
9
10 #include <assert.h>
11 #include <lk/compiler.h>
12
13 #include <arch/arm/cm.h>
14 #include <kernel/event.h>
15 #include <platform/rcc.h>
16 #include <sys/types.h>
17
18 #include <stm32f0xx.h>
19
20 typedef DMA_Channel_TypeDef dma_channel_regs_t;
21
22 event_t dma_events[DMA_CHANNELS];
23
dma_channel_assert(dma_channel_t chan)24 static void dma_channel_assert(dma_channel_t chan) {
25 assert(DMA_CHANNEL_1 <= chan && chan < DMA_CHANNEL_7);
26 }
27
dma_get_channel(dma_channel_t chan)28 static dma_channel_regs_t *dma_get_channel(dma_channel_t chan) {
29 unsigned long addr =
30 DMA1_Channel1_BASE + (chan - 1) * 0x14;
31 return (dma_channel_regs_t *)addr;
32 }
33
dma_event(dma_channel_t chan)34 static event_t *dma_event(dma_channel_t chan) {
35 return &dma_events[chan - 1];
36 }
37
38 // TODO(konkers): Separate out DMA IRQ handling by channel group.
dma_irq(void)39 void dma_irq(void) {
40 arm_cm_irq_entry();
41 bool resched = false;
42
43 uint32_t sr = DMA1->ISR;
44
45 size_t i;
46 for (i = 0; i < countof(dma_events); i++) {
47 uint32_t ch_sr = (sr >> (i * 4)) & 0xf;
48
49 // TODO(konkers): Report error.
50 if (ch_sr & (DMA_ISR_TCIF1 | DMA_ISR_TEIF1)) {
51 event_signal(&dma_events[i], false);
52 resched = true;
53 }
54 }
55 DMA1->IFCR = sr;
56 arm_cm_irq_exit(resched);
57 }
58
stm32_DMA1_Channel1_IRQ(void)59 void stm32_DMA1_Channel1_IRQ(void) {
60 dma_irq();
61 }
62
stm32_DMA1_Channel2_3_IRQ(void)63 void stm32_DMA1_Channel2_3_IRQ(void) {
64 dma_irq();
65 }
66
stm32_DMA1_Channel4_5_6_7_IRQ(void)67 void stm32_DMA1_Channel4_5_6_7_IRQ(void) {
68 dma_irq();
69 }
70
dma_transfer_start(dma_channel_t chan,uint32_t periph_addr,uint32_t mem_addr,uint16_t count,uint32_t flags)71 void dma_transfer_start(dma_channel_t chan,
72 uint32_t periph_addr,
73 uint32_t mem_addr,
74 uint16_t count,
75 uint32_t flags) {
76 dma_channel_assert(chan);
77 event_unsignal(dma_event(chan));
78
79 dma_channel_regs_t *chan_regs = dma_get_channel(chan);
80 chan_regs->CCR &= ~DMA_CCR_EN;
81
82 chan_regs->CPAR = periph_addr;
83 chan_regs->CMAR = mem_addr;
84 chan_regs->CNDTR = count;
85 chan_regs->CCR = flags | DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_EN;
86 }
87
dma_wait(dma_channel_t chan)88 void dma_wait(dma_channel_t chan) {
89 dma_channel_assert(chan);
90
91 event_wait(dma_event(chan));
92 }
93
dma_init(void)94 void dma_init(void) {
95 stm32_rcc_set_enable(STM32_RCC_CLK_DMA, true);
96
97 size_t i;
98 for (i = 0; i < countof(dma_events); i++) {
99 // Initialize all the channel events as signaled because they're idle.
100 event_init(&dma_events[i], true, 0);
101 }
102 NVIC_EnableIRQ(DMA1_Channel1_IRQn);
103 NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
104 NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
105 }
106