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 161 static inline struct StmDmaStreamState *dmaGetStreamState(uint8_t busId, 162 uint8_t stream) 163 { 164 return &gDmaDevs[busId].streams[stream]; 165 } 166 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 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 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 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 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 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 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 277 uint16_t dmaBytesLeft(uint8_t busId, uint8_t stream) 278 { 279 struct StmDmaStreamRegs *regs = dmaGetStreamRegs(busId, stream); 280 return regs->NDTR; 281 } 282 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 299 const enum IRQn dmaIrq(uint8_t busId, uint8_t stream) 300 { 301 return STM_DMA_IRQ[busId][stream]; 302 } 303 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