Home | History | Annotate | Download | only in stm32
      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