1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************************/
20 
21 /****** Includes *******/
22 #include <stddef.h>
23 #include <stdint.h>
24 #include "mxc_device.h"
25 #include "mxc_assert.h"
26 #include "mxc_lock.h"
27 #include "mxc_sys.h"
28 #include "dma.h"
29 #include "dma_reva.h"
30 #include "dma_reva_regs.h"
31 
32 /***** Definitions *****/
33 #define CHECK_HANDLE(x) ((x >= 0) && (x < MXC_DMA_CHANNELS) && (dma_resource[x].valid))
34 
35 typedef struct {
36     void *userCallback; // user given callback
37     void *dest; // memcpy destination
38 } mxc_dma_highlevel_t;
39 
40 typedef struct {
41     unsigned int valid; // Flag to invalidate this resource
42     unsigned int instance; // Hardware instance of this DMA controller
43     unsigned int id; // Channel ID, which matches the index into the underlying hardware
44     mxc_dma_reva_ch_regs_t *regs; // Pointer to the registers for this channel
45     void (*cb)(int, int); // Pointer to a callback function type
46 } mxc_dma_channel_t;
47 
48 /******* Globals *******/
49 static unsigned int dma_initialized[MXC_DMA_INSTANCES] = { 0 };
50 static mxc_dma_channel_t dma_resource[MXC_DMA_CHANNELS];
51 static mxc_dma_highlevel_t memcpy_resource[MXC_DMA_CHANNELS];
52 static uint32_t dma_lock;
53 
54 /****** Functions ******/
55 static void memcpy_callback(int ch, int error);
56 static void transfer_callback(int ch, int error);
57 
MXC_DMA_RevA_Init(mxc_dma_reva_regs_t * dma)58 int MXC_DMA_RevA_Init(mxc_dma_reva_regs_t *dma)
59 {
60     int i, numCh, offset;
61     int dma_idx;
62 
63     dma_idx = MXC_DMA_GET_IDX((mxc_dma_regs_t *)dma);
64     MXC_ASSERT(dma_idx >= 0);
65 
66 #if TARGET_NUM == 32665
67     numCh = MXC_DMA_CH_OFFSET;
68     offset = numCh * dma_idx;
69 #else
70     numCh = MXC_DMA_CHANNELS;
71     offset = 0;
72 #endif
73 
74     if (dma_initialized[dma_idx]) {
75         return E_BAD_STATE;
76     }
77 
78 #ifndef __riscv
79     /* Initialize mutex */
80     MXC_FreeLock(&dma_lock);
81 
82     if (MXC_GetLock(&dma_lock, 1) != E_NO_ERROR) {
83         return E_BUSY;
84     }
85 #endif
86 
87     /* Ensure all channels are disabled at start, clear flags, init handles */
88     dma->inten = 0;
89 
90     for (i = offset; i < (offset + numCh); i++) {
91         dma_resource[i].valid = 0;
92         dma_resource[i].instance = 0;
93         dma_resource[i].id = i;
94         dma_resource[i].regs = (mxc_dma_reva_ch_regs_t *)&(dma->ch[(i % numCh)]);
95         dma_resource[i].regs->ctrl = 0;
96         dma_resource[i].regs->status = dma_resource[i].regs->status;
97 
98         dma_resource[i].cb = NULL;
99     }
100 
101     dma_initialized[dma_idx]++;
102 #ifndef __riscv
103     MXC_FreeLock(&dma_lock);
104 #endif
105 
106     return E_NO_ERROR;
107 }
108 
MXC_DMA_RevA_DeInit(mxc_dma_reva_regs_t * dma)109 void MXC_DMA_RevA_DeInit(mxc_dma_reva_regs_t *dma)
110 {
111     int dma_idx;
112 
113     dma_idx = MXC_DMA_GET_IDX((mxc_dma_regs_t *)dma);
114     MXC_ASSERT(dma_idx >= 0);
115 
116     dma_initialized[dma_idx] = 0;
117 }
118 
MXC_DMA_RevA_AcquireChannel(mxc_dma_reva_regs_t * dma)119 int MXC_DMA_RevA_AcquireChannel(mxc_dma_reva_regs_t *dma)
120 {
121     int i, channel, numCh, offset;
122     int dma_idx;
123 
124     dma_idx = MXC_DMA_GET_IDX((mxc_dma_regs_t *)dma);
125     MXC_ASSERT(dma_idx >= 0);
126 
127     /* Check for initialization */
128     if (!dma_initialized[dma_idx]) {
129         return E_BAD_STATE;
130     }
131 
132 #if TARGET_NUM == 32665
133     numCh = MXC_DMA_CH_OFFSET;
134     offset = MXC_DMA_CH_OFFSET * dma_idx;
135 #else
136     numCh = MXC_DMA_CHANNELS;
137     offset = 0;
138 #endif
139 
140 #ifndef __riscv
141     /* If DMA is locked return busy */
142     if (MXC_GetLock(&dma_lock, 1) != E_NO_ERROR) {
143         return E_BUSY;
144     }
145 #endif
146     /* Default is no channel available */
147     channel = E_NONE_AVAIL;
148 
149     for (i = offset; i < (offset + numCh); i++) {
150         if (!dma_resource[i].valid) {
151             /* Found one */
152             channel = i;
153             dma_resource[i].valid = 1;
154             dma_resource[i].regs->ctrl = 0;
155             dma_resource[i].regs->cntrld = 0; /* Used by DMA_Start() to conditionally set RLDEN */
156             break;
157         }
158     }
159 #ifndef __riscv
160     MXC_FreeLock(&dma_lock);
161 #endif
162 
163     return channel;
164 }
165 
MXC_DMA_RevA_ReleaseChannel(int ch)166 int MXC_DMA_RevA_ReleaseChannel(int ch)
167 {
168     if (CHECK_HANDLE(ch)) {
169         if (MXC_GetLock(&dma_lock, 1) != E_NO_ERROR) {
170             return E_BUSY;
171         }
172 
173         dma_resource[ch].valid = 0;
174         dma_resource[ch].regs->ctrl = 0;
175         dma_resource[ch].regs->status = dma_resource[ch].regs->status;
176         MXC_FreeLock(&dma_lock);
177     } else {
178         return E_BAD_PARAM;
179     }
180 
181     return E_NO_ERROR;
182 }
183 
MXC_DMA_RevA_ConfigChannel(mxc_dma_config_t config,mxc_dma_srcdst_t srcdst)184 int MXC_DMA_RevA_ConfigChannel(mxc_dma_config_t config, mxc_dma_srcdst_t srcdst)
185 {
186     if (CHECK_HANDLE(config.ch)) {
187         /* Designed to be safe, not speedy. Should not be called often */
188         dma_resource[config.ch].regs->ctrl =
189             ((config.srcinc_en ? MXC_F_DMA_REVA_CTRL_SRCINC : 0) |
190              (config.dstinc_en ? MXC_F_DMA_REVA_CTRL_DSTINC : 0) | config.reqsel |
191              (config.srcwd << MXC_F_DMA_REVA_CTRL_SRCWD_POS) |
192              (config.dstwd << MXC_F_DMA_REVA_CTRL_DSTWD_POS));
193     } else {
194         return E_BAD_PARAM;
195     }
196 
197     return MXC_DMA_RevA_SetSrcDst(srcdst);
198 }
199 
MXC_DMA_RevA_AdvConfigChannel(mxc_dma_adv_config_t advConfig)200 int MXC_DMA_RevA_AdvConfigChannel(mxc_dma_adv_config_t advConfig)
201 {
202     if (CHECK_HANDLE(advConfig.ch) && (advConfig.burst_size > 0)) {
203         dma_resource[advConfig.ch].regs->ctrl &= ~(0x1F00FC0C); // Clear all fields we set here
204         /* Designed to be safe, not speedy. Should not be called often */
205         dma_resource[advConfig.ch].regs->ctrl |=
206             ((advConfig.reqwait_en ? MXC_F_DMA_REVA_CTRL_TO_WAIT : 0) | advConfig.prio |
207              advConfig.tosel | advConfig.pssel |
208              (((advConfig.burst_size - 1) << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS) &
209               MXC_F_DMA_REVA_CTRL_BURST_SIZE));
210     } else {
211         return E_BAD_PARAM;
212     }
213 
214     return E_NO_ERROR;
215 }
216 
MXC_DMA_RevA_SetSrcDst(mxc_dma_srcdst_t srcdst)217 int MXC_DMA_RevA_SetSrcDst(mxc_dma_srcdst_t srcdst)
218 {
219     if (CHECK_HANDLE(srcdst.ch)) {
220         dma_resource[srcdst.ch].regs->src = (unsigned int)srcdst.source;
221         dma_resource[srcdst.ch].regs->dst = (unsigned int)srcdst.dest;
222         dma_resource[srcdst.ch].regs->cnt = srcdst.len;
223     } else {
224         return E_BAD_PARAM;
225     }
226 
227     return E_NO_ERROR;
228 }
229 
MXC_DMA_RevA_GetSrcDst(mxc_dma_srcdst_t * srcdst)230 int MXC_DMA_RevA_GetSrcDst(mxc_dma_srcdst_t *srcdst)
231 {
232     if (CHECK_HANDLE(srcdst->ch)) {
233         srcdst->source = (void *)dma_resource[srcdst->ch].regs->src;
234         srcdst->dest = (void *)dma_resource[srcdst->ch].regs->dst;
235         srcdst->len = (dma_resource[srcdst->ch].regs->cnt) & ~MXC_F_DMA_REVA_CNTRLD_EN;
236     } else {
237         return E_BAD_PARAM;
238     }
239 
240     return E_NO_ERROR;
241 }
242 
MXC_DMA_RevA_SetSrcReload(mxc_dma_srcdst_t srcdst)243 int MXC_DMA_RevA_SetSrcReload(mxc_dma_srcdst_t srcdst)
244 {
245     if (CHECK_HANDLE(srcdst.ch)) {
246         dma_resource[srcdst.ch].regs->srcrld = (unsigned int)srcdst.source;
247         dma_resource[srcdst.ch].regs->dstrld = (unsigned int)srcdst.dest;
248 
249         if (dma_resource[srcdst.ch].regs->ctrl & MXC_F_DMA_REVA_CTRL_EN) {
250             /* If channel is already running, set RLDEN to enable next reload */
251             dma_resource[srcdst.ch].regs->cntrld = MXC_F_DMA_REVA_CNTRLD_EN | srcdst.len;
252         } else {
253             /* Otherwise, this is the initial setup, so DMA_Start() will handle setting that bit */
254             dma_resource[srcdst.ch].regs->cntrld = srcdst.len;
255         }
256     } else {
257         return E_BAD_PARAM;
258     }
259 
260     return E_NO_ERROR;
261 }
262 
MXC_DMA_RevA_GetSrcReload(mxc_dma_srcdst_t * srcdst)263 int MXC_DMA_RevA_GetSrcReload(mxc_dma_srcdst_t *srcdst)
264 {
265     if (CHECK_HANDLE(srcdst->ch)) {
266         srcdst->source = (void *)dma_resource[srcdst->ch].regs->srcrld;
267         srcdst->dest = (void *)dma_resource[srcdst->ch].regs->dstrld;
268         srcdst->len = (dma_resource[srcdst->ch].regs->cntrld) & ~MXC_F_DMA_REVA_CNTRLD_EN;
269     } else {
270         return E_BAD_PARAM;
271     }
272 
273     return E_NO_ERROR;
274 }
275 
MXC_DMA_RevA_SetCallback(int ch,void (* callback)(int,int))276 int MXC_DMA_RevA_SetCallback(int ch, void (*callback)(int, int))
277 {
278     if (CHECK_HANDLE(ch)) {
279         /* Callback for interrupt handler, no checking is done, as NULL is valid for(none)  */
280         dma_resource[ch].cb = callback;
281     } else {
282         return E_BAD_PARAM;
283     }
284 
285     return E_NO_ERROR;
286 }
287 
MXC_DMA_RevA_SetChannelInterruptEn(int ch,bool chdis,bool ctz)288 int MXC_DMA_RevA_SetChannelInterruptEn(int ch, bool chdis, bool ctz)
289 {
290     if (CHECK_HANDLE(ch)) {
291         if (chdis) {
292             dma_resource[ch].regs->ctrl |= (MXC_F_DMA_REVA_CTRL_DIS_IE);
293         }
294         if (ctz) {
295             dma_resource[ch].regs->ctrl |= (MXC_F_DMA_REVA_CTRL_CTZ_IE);
296         }
297     } else {
298         return E_BAD_PARAM;
299     }
300 
301     return E_NO_ERROR;
302 }
303 
MXC_DMA_RevA_GetChannelInterruptEn(int ch)304 int MXC_DMA_RevA_GetChannelInterruptEn(int ch)
305 {
306     return E_NOT_SUPPORTED;
307 }
308 
MXC_DMA_RevA_ChannelEnableInt(int ch,int flags)309 int MXC_DMA_RevA_ChannelEnableInt(int ch, int flags)
310 {
311     if (CHECK_HANDLE(ch)) {
312         dma_resource[ch].regs->ctrl |=
313             (flags & (MXC_F_DMA_REVA_CTRL_DIS_IE | MXC_F_DMA_REVA_CTRL_CTZ_IE));
314     } else {
315         return E_BAD_PARAM;
316     }
317 
318     return E_NO_ERROR;
319 }
320 
MXC_DMA_RevA_ChannelDisableInt(int ch,int flags)321 int MXC_DMA_RevA_ChannelDisableInt(int ch, int flags)
322 {
323     if (CHECK_HANDLE(ch)) {
324         dma_resource[ch].regs->ctrl &=
325             ~(flags & (MXC_F_DMA_REVA_CTRL_DIS_IE | MXC_F_DMA_REVA_CTRL_CTZ_IE));
326     } else {
327         return E_BAD_PARAM;
328     }
329 
330     return E_NO_ERROR;
331 }
332 
MXC_DMA_RevA_EnableInt(mxc_dma_reva_regs_t * dma,int ch)333 int MXC_DMA_RevA_EnableInt(mxc_dma_reva_regs_t *dma, int ch)
334 {
335     if (CHECK_HANDLE(ch)) {
336 #if TARGET_NUM == 32665
337         ch %= MXC_DMA_CH_OFFSET;
338 #endif
339         dma->inten |= (1 << ch);
340     } else {
341         return E_BAD_PARAM;
342     }
343 
344     return E_NO_ERROR;
345 }
346 
MXC_DMA_RevA_DisableInt(mxc_dma_reva_regs_t * dma,int ch)347 int MXC_DMA_RevA_DisableInt(mxc_dma_reva_regs_t *dma, int ch)
348 {
349     if (CHECK_HANDLE(ch)) {
350 #if TARGET_NUM == 32665
351         ch %= MXC_DMA_CH_OFFSET;
352 #endif
353         dma->inten &= ~(1 << ch);
354     } else {
355         return E_BAD_PARAM;
356     }
357 
358     return E_NO_ERROR;
359 }
360 
MXC_DMA_RevA_ChannelGetFlags(int ch)361 int MXC_DMA_RevA_ChannelGetFlags(int ch)
362 {
363     if (CHECK_HANDLE(ch)) {
364         return dma_resource[ch].regs->status;
365     } else {
366         return E_BAD_PARAM;
367     }
368 }
369 
MXC_DMA_RevA_ChannelClearFlags(int ch,int flags)370 int MXC_DMA_RevA_ChannelClearFlags(int ch, int flags)
371 {
372     if (CHECK_HANDLE(ch)) {
373         dma_resource[ch].regs->status |= (flags & 0x5F); // Mask for Interrupt flags
374     } else {
375         return E_BAD_PARAM;
376     }
377 
378     return E_NO_ERROR;
379 }
380 
MXC_DMA_RevA_Start(int ch)381 int MXC_DMA_RevA_Start(int ch)
382 {
383     if (CHECK_HANDLE(ch)) {
384         MXC_DMA_ChannelClearFlags(ch, MXC_DMA_RevA_ChannelGetFlags(ch));
385 
386         if (dma_resource[ch].regs->cntrld) {
387             dma_resource[ch].regs->ctrl |= (MXC_F_DMA_REVA_CTRL_EN | MXC_F_DMA_REVA_CTRL_RLDEN);
388         } else {
389             dma_resource[ch].regs->ctrl |= MXC_F_DMA_REVA_CTRL_EN;
390         }
391     } else {
392         return E_BAD_PARAM;
393     }
394 
395     return E_NO_ERROR;
396 }
397 
MXC_DMA_RevA_Stop(int ch)398 int MXC_DMA_RevA_Stop(int ch)
399 {
400     if (CHECK_HANDLE(ch)) {
401         dma_resource[ch].regs->ctrl &= ~MXC_F_DMA_REVA_CTRL_EN;
402     } else {
403         return E_BAD_PARAM;
404     }
405 
406     return E_NO_ERROR;
407 }
408 
MXC_DMA_RevA_GetCHRegs(int ch)409 mxc_dma_ch_regs_t *MXC_DMA_RevA_GetCHRegs(int ch)
410 {
411     if (CHECK_HANDLE(ch)) {
412         return (mxc_dma_ch_regs_t *)dma_resource[ch].regs;
413     } else {
414         return NULL;
415     }
416 }
417 
MXC_DMA_RevA_Handler(mxc_dma_reva_regs_t * dma)418 void MXC_DMA_RevA_Handler(mxc_dma_reva_regs_t *dma)
419 {
420     int numCh = MXC_DMA_CHANNELS / MXC_DMA_INSTANCES;
421     int dma_idx;
422     int offset;
423 
424     dma_idx = MXC_DMA_GET_IDX((mxc_dma_regs_t *)dma);
425     MXC_ASSERT(dma_idx >= 0);
426 
427     offset = numCh * dma_idx;
428     /* Do callback, if enabled */
429     for (int i = offset; i < (offset + numCh); i++) {
430         if (CHECK_HANDLE(i)) {
431             if (dma->intfl & (0x1 << (i % numCh))) {
432                 if (dma_resource[i].cb != NULL) {
433                     dma_resource[i].cb(i, E_NO_ERROR);
434                 }
435 
436                 MXC_DMA_ChannelClearFlags(i, MXC_DMA_RevA_ChannelGetFlags(i));
437 
438                 // No need to check rest of the channels if no interrupt flags set.
439                 if (dma->intfl == 0) {
440                     break;
441                 }
442             }
443         }
444     }
445 }
446 
memcpy_callback(int ch,int error)447 void memcpy_callback(int ch, int error)
448 {
449     mxc_dma_complete_cb_t callback;
450     callback = (mxc_dma_complete_cb_t)memcpy_resource[ch].userCallback;
451 
452     if (error != E_NO_ERROR) {
453         callback(NULL);
454     }
455 
456     callback(memcpy_resource[ch].dest);
457 
458     // Release global objects and local resources
459     callback = NULL;
460     memcpy_resource[ch].userCallback = NULL;
461     memcpy_resource[ch].dest = NULL;
462     MXC_DMA_ReleaseChannel(ch);
463 }
464 
MXC_DMA_RevA_MemCpy(mxc_dma_reva_regs_t * dma,void * dest,void * src,int len,mxc_dma_complete_cb_t callback)465 int MXC_DMA_RevA_MemCpy(mxc_dma_reva_regs_t *dma, void *dest, void *src, int len,
466                         mxc_dma_complete_cb_t callback)
467 {
468     int retval;
469     mxc_dma_config_t config;
470     mxc_dma_srcdst_t transfer;
471     int channel;
472 
473 #if TARGET_NUM == 32665
474     channel = MXC_DMA_AcquireChannel((mxc_dma_regs_t *)dma);
475 #else
476     channel = MXC_DMA_AcquireChannel();
477 #endif
478 
479     if (memcpy_resource[channel].userCallback != NULL) {
480         // We acquired a channel we haven't cleared yet
481         MXC_DMA_ReleaseChannel(channel);
482         return E_UNKNOWN;
483     }
484 
485     transfer.ch = channel;
486     transfer.source = src;
487     transfer.dest = dest;
488     transfer.len = len;
489 
490     config.ch = channel;
491     config.reqsel = MXC_DMA_REQUEST_MEMTOMEM;
492     config.srcwd = MXC_DMA_WIDTH_WORD;
493     config.dstwd = MXC_DMA_WIDTH_WORD;
494     config.srcinc_en = 1;
495     config.dstinc_en = 1;
496 
497     retval = MXC_DMA_ConfigChannel(config, transfer);
498 
499     if (retval != E_NO_ERROR) {
500         return retval;
501     }
502 
503     retval = MXC_DMA_EnableInt(channel);
504 
505     if (retval != E_NO_ERROR) {
506         return retval;
507     }
508 
509     retval = MXC_DMA_ChannelEnableInt(channel, MXC_F_DMA_REVA_CTRL_CTZ_IE);
510 
511     if (retval != E_NO_ERROR) {
512         return retval;
513     }
514 
515     MXC_DMA_SetCallback(channel, memcpy_callback);
516 
517     memcpy_resource[channel].userCallback = (void *)callback;
518     memcpy_resource[channel].dest = dest;
519 
520     return MXC_DMA_Start(channel);
521 }
522 
transfer_callback(int ch,int error)523 void transfer_callback(int ch, int error)
524 {
525     // Unimplemented
526     // Check for reason
527     // Call user callback for next transfer
528     // determine whether to load into the transfer slot or reload slot
529     // continue on or stop
530     while (1) {}
531 }
532 
MXC_DMA_RevA_DoTransfer(mxc_dma_reva_regs_t * dma,mxc_dma_config_t config,mxc_dma_srcdst_t firstSrcDst,mxc_dma_trans_chain_t callback)533 int MXC_DMA_RevA_DoTransfer(mxc_dma_reva_regs_t *dma, mxc_dma_config_t config,
534                             mxc_dma_srcdst_t firstSrcDst, mxc_dma_trans_chain_t callback)
535 {
536     int retval, channel;
537 
538 #if TARGET_NUM == 32665
539     channel = MXC_DMA_AcquireChannel((mxc_dma_regs_t *)dma);
540 #else
541     channel = MXC_DMA_AcquireChannel();
542 #endif
543 
544     if (memcpy_resource[channel].userCallback != NULL) {
545         // We acquired a channel we haven't cleared yet
546         MXC_DMA_ReleaseChannel(channel);
547         return E_UNKNOWN;
548     }
549 
550     retval = MXC_DMA_ConfigChannel(config, firstSrcDst);
551 
552     if (retval != E_NO_ERROR) {
553         return retval;
554     }
555 
556     retval = MXC_DMA_EnableInt(channel);
557 
558     if (retval != E_NO_ERROR) {
559         return retval;
560     }
561 
562     retval = MXC_DMA_ChannelEnableInt(channel, MXC_F_DMA_REVA_CTRL_CTZ_IE);
563 
564     if (retval != E_NO_ERROR) {
565         return retval;
566     }
567 
568     MXC_DMA_SetCallback(channel, transfer_callback);
569 
570     memcpy_resource[channel].userCallback = (void *)callback;
571 
572     return MXC_DMA_Start(channel);
573 }
574