1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <errno.h>
18 
19 #include <heap.h>
20 #include <seos.h>
21 #include <util.h>
22 
23 #include <plat/cmsis.h>
24 #include <plat/dma.h>
25 #include <plat/pwr.h>
26 
27 #define DMA_VERBOSE_DEBUG 0
28 
29 #if DMA_VERBOSE_DEBUG
30 #define dmaLogDebug(x) osLog(LOG_DEBUG, x "\n")
31 #else
32 #define dmaLogDebug(x) do {} while(0)
33 #endif
34 
35 #define STM_DMA_NUM_DEVS 2
36 #define STM_DMA_NUM_STREAMS 8
37 
38 struct StmDmaStreamRegs {
39     volatile uint32_t CR;
40     volatile uint32_t NDTR;
41     volatile uint32_t PAR;
42     volatile uint32_t M0AR;
43     volatile uint32_t M1AR;
44     volatile uint32_t FCR;
45 };
46 
47 struct StmDmaRegs {
48     volatile uint32_t LISR;
49     volatile uint32_t HISR;
50     volatile uint32_t LIFCR;
51     volatile uint32_t HIFCR;
52     struct StmDmaStreamRegs Sx[STM_DMA_NUM_STREAMS];
53 };
54 
55 #define STM_DMA_ISR_FEIFx               (1 << 0)
56 #define STM_DMA_ISR_DMEIFx              (1 << 2)
57 #define STM_DMA_ISR_TEIFx               (1 << 3)
58 #define STM_DMA_ISR_HTIFx               (1 << 4)
59 #define STM_DMA_ISR_TCIFx               (1 << 5)
60 #define STM_DMA_ISR_MASK \
61     (STM_DMA_ISR_FEIFx | STM_DMA_ISR_DMEIFx | STM_DMA_ISR_TEIFx | \
62      STM_DMA_ISR_HTIFx | STM_DMA_ISR_TCIFx)
63 
64 #define STM_DMA_CR_EN                   (1 << 0)
65 #define STM_DMA_CR_DMEIE                (1 << 1)
66 #define STM_DMA_CR_TEIE                 (1 << 2)
67 #define STM_DMA_CR_HTIE                 (1 << 3)
68 #define STM_DMA_CR_TCIE                 (1 << 4)
69 #define STM_DMA_CR_PFCTRL               (1 << 5)
70 
71 #define STM_DMA_CR_DIR(x)               ((x) << 6)
72 
73 #define STM_DMA_CR_MINC                 (1 << 10)
74 
75 #define STM_DMA_CR_PSIZE(x)             ((x) << 11)
76 
77 #define STM_DMA_CR_MSIZE(x)             ((x) << 13)
78 
79 #define STM_DMA_CR_PL(x)                ((x) << 16)
80 #define STM_DMA_CR_PBURST(x)            ((x) << 21)
81 #define STM_DMA_CR_MBURST(x)            ((x) << 23)
82 
83 #define STM_DMA_CR_CHSEL(x)             ((x) << 25)
84 #define STM_DMA_CR_CHSEL_MASK           STM_DMA_CR_CHSEL(0x7)
85 
86 struct StmDmaStreamState {
87     DmaCallbackF callback;
88     void *cookie;
89     uint16_t tid;
90     uint16_t reserved;
91 };
92 
93 struct StmDmaDev {
94     struct StmDmaRegs *const regs;
95     struct StmDmaStreamState streams[STM_DMA_NUM_STREAMS];
96 };
97 
98 static void dmaIsr(uint8_t busId, uint8_t stream);
99 
100 #define DECLARE_IRQ_HANDLER(_n, _s)                             \
101     extern void DMA##_n##_Stream##_s##_IRQHandler(void);        \
102     void DMA##_n##_Stream##_s##_IRQHandler(void)                \
103     {                                                           \
104         dmaIsr(_n - 1, _s);                                     \
105     }
106 
107 static struct StmDmaDev gDmaDevs[STM_DMA_NUM_DEVS] = {
108     [0] = {
109         .regs = (struct StmDmaRegs *)DMA1_BASE,
110     },
111     [1] = {
112         .regs = (struct StmDmaRegs *)DMA2_BASE,
113     },
114 };
115 DECLARE_IRQ_HANDLER(1, 0)
116 DECLARE_IRQ_HANDLER(1, 1)
117 DECLARE_IRQ_HANDLER(1, 2)
118 DECLARE_IRQ_HANDLER(1, 3)
119 DECLARE_IRQ_HANDLER(1, 4)
120 DECLARE_IRQ_HANDLER(1, 5)
121 DECLARE_IRQ_HANDLER(1, 6)
122 DECLARE_IRQ_HANDLER(1, 7)
123 DECLARE_IRQ_HANDLER(2, 0)
124 DECLARE_IRQ_HANDLER(2, 1)
125 DECLARE_IRQ_HANDLER(2, 2)
126 DECLARE_IRQ_HANDLER(2, 3)
127 DECLARE_IRQ_HANDLER(2, 4)
128 DECLARE_IRQ_HANDLER(2, 5)
129 DECLARE_IRQ_HANDLER(2, 6)
130 DECLARE_IRQ_HANDLER(2, 7)
131 
132 static const enum IRQn STM_DMA_IRQ[STM_DMA_NUM_DEVS][STM_DMA_NUM_STREAMS] = {
133     [0] = {
134         DMA1_Stream0_IRQn,
135         DMA1_Stream1_IRQn,
136         DMA1_Stream2_IRQn,
137         DMA1_Stream3_IRQn,
138         DMA1_Stream4_IRQn,
139         DMA1_Stream5_IRQn,
140         DMA1_Stream6_IRQn,
141         DMA1_Stream7_IRQn,
142     },
143     [1] = {
144         DMA2_Stream0_IRQn,
145         DMA2_Stream1_IRQn,
146         DMA2_Stream2_IRQn,
147         DMA2_Stream3_IRQn,
148         DMA2_Stream4_IRQn,
149         DMA2_Stream5_IRQn,
150         DMA2_Stream6_IRQn,
151         DMA2_Stream7_IRQn,
152     },
153 };
154 
155 
156 static const uint32_t STM_DMA_CLOCK_UNIT[STM_DMA_NUM_DEVS] = {
157     PERIPH_AHB1_DMA1,
158     PERIPH_AHB1_DMA2
159 };
160 
dmaGetStreamState(uint8_t busId,uint8_t stream)161 static inline struct StmDmaStreamState *dmaGetStreamState(uint8_t busId,
162         uint8_t stream)
163 {
164     return &gDmaDevs[busId].streams[stream];
165 }
166 
dmaGetStreamRegs(uint8_t busId,uint8_t stream)167 static inline struct StmDmaStreamRegs *dmaGetStreamRegs(uint8_t busId,
168         uint8_t stream)
169 {
170     return &gDmaDevs[busId].regs->Sx[stream];
171 }
172 
173 static const unsigned int STM_DMA_FEIFx_OFFSET[] = { 0, 6, 16, 22 };
174 
dmaGetIsr(uint8_t busId,uint8_t stream)175 static inline uint8_t dmaGetIsr(uint8_t busId, uint8_t stream)
176 {
177     struct StmDmaDev *dev = &gDmaDevs[busId];
178     if (stream < 4)
179         return (dev->regs->LISR >> STM_DMA_FEIFx_OFFSET[stream]) & STM_DMA_ISR_MASK;
180     else
181         return (dev->regs->HISR >> STM_DMA_FEIFx_OFFSET[stream - 4]) & STM_DMA_ISR_MASK;
182 }
183 
dmaClearIsr(uint8_t busId,uint8_t stream,uint8_t mask)184 static inline void dmaClearIsr(uint8_t busId, uint8_t stream, uint8_t mask)
185 {
186     struct StmDmaDev *dev = &gDmaDevs[busId];
187     if (stream < 4)
188         dev->regs->LIFCR = mask << STM_DMA_FEIFx_OFFSET[stream];
189     else
190         dev->regs->HIFCR = mask << STM_DMA_FEIFx_OFFSET[stream - 4];
191 }
192 
dmaIsrTeif(uint8_t busId,uint8_t stream)193 static void dmaIsrTeif(uint8_t busId, uint8_t stream)
194 {
195     struct StmDmaStreamState *state = dmaGetStreamState(busId, stream);
196     struct StmDmaStreamRegs *regs = dmaGetStreamRegs(busId, stream);
197 
198     dmaLogDebug("teif");
199     dmaStop(busId, stream);
200 
201     uint16_t oldTid = osSetCurrentTid(state->tid);
202     state->callback(state->cookie, regs->NDTR, EIO);
203     osSetCurrentTid(oldTid);
204 }
205 
dmaIsrTcif(uint8_t busId,uint8_t stream)206 static void dmaIsrTcif(uint8_t busId, uint8_t stream)
207 {
208     struct StmDmaStreamState *state = dmaGetStreamState(busId, stream);
209     struct StmDmaStreamRegs *regs = dmaGetStreamRegs(busId, stream);
210 
211     dmaLogDebug("tcif");
212     dmaStop(busId, stream);
213 
214     uint16_t oldTid = osSetCurrentTid(state->tid);
215     state->callback(state->cookie, regs->NDTR, 0);
216     osSetCurrentTid(oldTid);
217 }
218 
dmaIsr(uint8_t busId,uint8_t stream)219 static void dmaIsr(uint8_t busId, uint8_t stream)
220 {
221     struct StmDmaStreamState *state = dmaGetStreamState(busId, stream);
222 
223     if (UNLIKELY(!state->callback)) {
224         osLog(LOG_WARN, "DMA %u stream %u ISR fired while disabled\n",
225                 busId, stream);
226         dmaStop(busId, stream);
227         return;
228     }
229 
230     uint8_t isr = dmaGetIsr(busId, stream);
231 
232     if (isr & STM_DMA_ISR_TEIFx)
233         dmaIsrTeif(busId, stream);
234     else if (isr & STM_DMA_ISR_TCIFx)
235         dmaIsrTcif(busId, stream);
236 }
237 
dmaStart(uint8_t busId,uint8_t stream,const void * buf,uint16_t size,const struct dmaMode * mode,DmaCallbackF callback,void * cookie)238 int dmaStart(uint8_t busId, uint8_t stream, const void *buf, uint16_t size,
239         const struct dmaMode *mode, DmaCallbackF callback, void *cookie)
240 {
241     if (busId >= STM_DMA_NUM_DEVS || stream >= STM_DMA_NUM_STREAMS)
242         return -EINVAL;
243 
244     struct StmDmaStreamState *state = dmaGetStreamState(busId, stream);
245     state->callback = callback;
246     state->cookie = cookie;
247     state->tid = osGetCurrentTid();
248 
249     pwrUnitClock(PERIPH_BUS_AHB1, STM_DMA_CLOCK_UNIT[busId], true);
250 
251     struct StmDmaStreamRegs *regs = dmaGetStreamRegs(busId, stream);
252     dmaClearIsr(busId, stream, STM_DMA_ISR_TEIFx);
253     dmaClearIsr(busId, stream, STM_DMA_ISR_TCIFx);
254 
255     regs->NDTR = size;
256     regs->PAR = mode->periphAddr;
257     regs->M0AR = (uintptr_t)buf;
258     regs->FCR = 0;
259     regs->CR = STM_DMA_CR_TEIE |
260             STM_DMA_CR_TCIE |
261             STM_DMA_CR_DIR(mode->direction) |
262             STM_DMA_CR_PSIZE(mode->psize) |
263             STM_DMA_CR_MSIZE(mode->msize) |
264             STM_DMA_CR_PL(mode->priority) |
265             STM_DMA_CR_PBURST(mode->pburst) |
266             STM_DMA_CR_MBURST(mode->mburst) |
267             STM_DMA_CR_CHSEL(mode->channel);
268     if (mode->minc)
269         regs->CR |= STM_DMA_CR_MINC;
270 
271     NVIC_EnableIRQ(STM_DMA_IRQ[busId][stream]);
272 
273     regs->CR |= STM_DMA_CR_EN;
274     return 0;
275 }
276 
dmaBytesLeft(uint8_t busId,uint8_t stream)277 uint16_t dmaBytesLeft(uint8_t busId, uint8_t stream)
278 {
279     struct StmDmaStreamRegs *regs = dmaGetStreamRegs(busId, stream);
280     return regs->NDTR;
281 }
282 
dmaStop(uint8_t busId,uint8_t stream)283 void dmaStop(uint8_t busId, uint8_t stream)
284 {
285     struct StmDmaStreamRegs *regs = dmaGetStreamRegs(busId, stream);
286     struct StmDmaStreamState *state = dmaGetStreamState(busId, stream);
287 
288     state->tid = 0;
289     dmaClearIsr(busId, stream, STM_DMA_ISR_TEIFx);
290     dmaClearIsr(busId, stream, STM_DMA_ISR_TCIFx);
291     NVIC_DisableIRQ(STM_DMA_IRQ[busId][stream]);
292 
293     regs->CR &= ~STM_DMA_CR_EN;
294     while (regs->CR & STM_DMA_CR_EN)
295         ;
296 
297 }
298 
dmaIrq(uint8_t busId,uint8_t stream)299 const enum IRQn dmaIrq(uint8_t busId, uint8_t stream)
300 {
301     return STM_DMA_IRQ[busId][stream];
302 }
303 
dmaStopAll(uint32_t tid)304 int dmaStopAll(uint32_t tid)
305 {
306     int busId, stream, count = 0;
307 
308     for (busId = 0; busId < STM_DMA_NUM_DEVS; ++busId) {
309         for (stream = 0; stream < STM_DMA_NUM_STREAMS; ++stream) {
310             struct StmDmaStreamState *state = dmaGetStreamState(busId, stream);
311             if (state->tid == tid) {
312                 dmaStop(busId, stream);
313                 count++;
314             }
315         }
316     }
317 
318     return count;
319 }
320