Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
10820 views
1
/*****************************************************************************
2
* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
3
*
4
* Unless you and Broadcom execute a separate written software license
5
* agreement governing use of this software, this software is licensed to you
6
* under the terms of the GNU General Public License version 2, available at
7
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8
*
9
* Notwithstanding the above, under no circumstances may you combine this
10
* software in any way with any other Broadcom software provided under a
11
* license other than the GPL, without Broadcom's express prior written
12
* consent.
13
*****************************************************************************/
14
15
/****************************************************************************/
16
/**
17
* @file dmacHw_extra.c
18
*
19
* @brief Extra Low level DMA controller driver routines
20
*
21
* @note
22
*
23
* These routines provide basic DMA functionality only.
24
*/
25
/****************************************************************************/
26
27
/* ---- Include Files ---------------------------------------------------- */
28
29
#include <csp/stdint.h>
30
#include <stddef.h>
31
32
#include <csp/dmacHw.h>
33
#include <mach/csp/dmacHw_reg.h>
34
#include <mach/csp/dmacHw_priv.h>
35
36
extern dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT]; /* Declared in dmacHw.c */
37
38
/* ---- External Function Prototypes ------------------------------------- */
39
40
/* ---- Internal Use Function Prototypes --------------------------------- */
41
/****************************************************************************/
42
/**
43
* @brief Overwrites data length in the descriptor
44
*
45
* This function overwrites data length in the descriptor
46
*
47
*
48
* @return void
49
*
50
* @note
51
* This is only used for PCM channel
52
*/
53
/****************************************************************************/
54
void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
55
void *pDescriptor, /* [ IN ] Descriptor buffer */
56
size_t dataLen /* [ IN ] Data length in bytes */
57
);
58
59
/****************************************************************************/
60
/**
61
* @brief Helper function to display DMA registers
62
*
63
* @return void
64
*
65
*
66
* @note
67
* None
68
*/
69
/****************************************************************************/
70
static void DisplayRegisterContents(int module, /* [ IN ] DMA Controller unit (0-1) */
71
int channel, /* [ IN ] DMA Channel (0-7) / -1(all) */
72
int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
73
) {
74
int chan;
75
76
(*fpPrint) ("Displaying register content \n\n");
77
(*fpPrint) ("Module %d: Interrupt raw transfer 0x%X\n",
78
module, (uint32_t) (dmacHw_REG_INT_RAW_TRAN(module)));
79
(*fpPrint) ("Module %d: Interrupt raw block 0x%X\n",
80
module, (uint32_t) (dmacHw_REG_INT_RAW_BLOCK(module)));
81
(*fpPrint) ("Module %d: Interrupt raw src transfer 0x%X\n",
82
module, (uint32_t) (dmacHw_REG_INT_RAW_STRAN(module)));
83
(*fpPrint) ("Module %d: Interrupt raw dst transfer 0x%X\n",
84
module, (uint32_t) (dmacHw_REG_INT_RAW_DTRAN(module)));
85
(*fpPrint) ("Module %d: Interrupt raw error 0x%X\n",
86
module, (uint32_t) (dmacHw_REG_INT_RAW_ERROR(module)));
87
(*fpPrint) ("--------------------------------------------------\n");
88
(*fpPrint) ("Module %d: Interrupt stat transfer 0x%X\n",
89
module, (uint32_t) (dmacHw_REG_INT_STAT_TRAN(module)));
90
(*fpPrint) ("Module %d: Interrupt stat block 0x%X\n",
91
module, (uint32_t) (dmacHw_REG_INT_STAT_BLOCK(module)));
92
(*fpPrint) ("Module %d: Interrupt stat src transfer 0x%X\n",
93
module, (uint32_t) (dmacHw_REG_INT_STAT_STRAN(module)));
94
(*fpPrint) ("Module %d: Interrupt stat dst transfer 0x%X\n",
95
module, (uint32_t) (dmacHw_REG_INT_STAT_DTRAN(module)));
96
(*fpPrint) ("Module %d: Interrupt stat error 0x%X\n",
97
module, (uint32_t) (dmacHw_REG_INT_STAT_ERROR(module)));
98
(*fpPrint) ("--------------------------------------------------\n");
99
(*fpPrint) ("Module %d: Interrupt mask transfer 0x%X\n",
100
module, (uint32_t) (dmacHw_REG_INT_MASK_TRAN(module)));
101
(*fpPrint) ("Module %d: Interrupt mask block 0x%X\n",
102
module, (uint32_t) (dmacHw_REG_INT_MASK_BLOCK(module)));
103
(*fpPrint) ("Module %d: Interrupt mask src transfer 0x%X\n",
104
module, (uint32_t) (dmacHw_REG_INT_MASK_STRAN(module)));
105
(*fpPrint) ("Module %d: Interrupt mask dst transfer 0x%X\n",
106
module, (uint32_t) (dmacHw_REG_INT_MASK_DTRAN(module)));
107
(*fpPrint) ("Module %d: Interrupt mask error 0x%X\n",
108
module, (uint32_t) (dmacHw_REG_INT_MASK_ERROR(module)));
109
(*fpPrint) ("--------------------------------------------------\n");
110
(*fpPrint) ("Module %d: Interrupt clear transfer 0x%X\n",
111
module, (uint32_t) (dmacHw_REG_INT_CLEAR_TRAN(module)));
112
(*fpPrint) ("Module %d: Interrupt clear block 0x%X\n",
113
module, (uint32_t) (dmacHw_REG_INT_CLEAR_BLOCK(module)));
114
(*fpPrint) ("Module %d: Interrupt clear src transfer 0x%X\n",
115
module, (uint32_t) (dmacHw_REG_INT_CLEAR_STRAN(module)));
116
(*fpPrint) ("Module %d: Interrupt clear dst transfer 0x%X\n",
117
module, (uint32_t) (dmacHw_REG_INT_CLEAR_DTRAN(module)));
118
(*fpPrint) ("Module %d: Interrupt clear error 0x%X\n",
119
module, (uint32_t) (dmacHw_REG_INT_CLEAR_ERROR(module)));
120
(*fpPrint) ("--------------------------------------------------\n");
121
(*fpPrint) ("Module %d: SW source req 0x%X\n",
122
module, (uint32_t) (dmacHw_REG_SW_HS_SRC_REQ(module)));
123
(*fpPrint) ("Module %d: SW dest req 0x%X\n",
124
module, (uint32_t) (dmacHw_REG_SW_HS_DST_REQ(module)));
125
(*fpPrint) ("Module %d: SW source signal 0x%X\n",
126
module, (uint32_t) (dmacHw_REG_SW_HS_SRC_SGL_REQ(module)));
127
(*fpPrint) ("Module %d: SW dest signal 0x%X\n",
128
module, (uint32_t) (dmacHw_REG_SW_HS_DST_SGL_REQ(module)));
129
(*fpPrint) ("Module %d: SW source last 0x%X\n",
130
module, (uint32_t) (dmacHw_REG_SW_HS_SRC_LST_REQ(module)));
131
(*fpPrint) ("Module %d: SW dest last 0x%X\n",
132
module, (uint32_t) (dmacHw_REG_SW_HS_DST_LST_REQ(module)));
133
(*fpPrint) ("--------------------------------------------------\n");
134
(*fpPrint) ("Module %d: misc config 0x%X\n",
135
module, (uint32_t) (dmacHw_REG_MISC_CFG(module)));
136
(*fpPrint) ("Module %d: misc channel enable 0x%X\n",
137
module, (uint32_t) (dmacHw_REG_MISC_CH_ENABLE(module)));
138
(*fpPrint) ("Module %d: misc ID 0x%X\n",
139
module, (uint32_t) (dmacHw_REG_MISC_ID(module)));
140
(*fpPrint) ("Module %d: misc test 0x%X\n",
141
module, (uint32_t) (dmacHw_REG_MISC_TEST(module)));
142
143
if (channel == -1) {
144
for (chan = 0; chan < 8; chan++) {
145
(*fpPrint)
146
("--------------------------------------------------\n");
147
(*fpPrint)
148
("Module %d: Channel %d Source 0x%X\n",
149
module, chan,
150
(uint32_t) (dmacHw_REG_SAR(module, chan)));
151
(*fpPrint)
152
("Module %d: Channel %d Destination 0x%X\n",
153
module, chan,
154
(uint32_t) (dmacHw_REG_DAR(module, chan)));
155
(*fpPrint)
156
("Module %d: Channel %d LLP 0x%X\n",
157
module, chan,
158
(uint32_t) (dmacHw_REG_LLP(module, chan)));
159
(*fpPrint)
160
("Module %d: Channel %d Control (LO) 0x%X\n",
161
module, chan,
162
(uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
163
(*fpPrint)
164
("Module %d: Channel %d Control (HI) 0x%X\n",
165
module, chan,
166
(uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
167
(*fpPrint)
168
("Module %d: Channel %d Source Stats 0x%X\n",
169
module, chan,
170
(uint32_t) (dmacHw_REG_SSTAT(module, chan)));
171
(*fpPrint)
172
("Module %d: Channel %d Dest Stats 0x%X\n",
173
module, chan,
174
(uint32_t) (dmacHw_REG_DSTAT(module, chan)));
175
(*fpPrint)
176
("Module %d: Channel %d Source Stats Addr 0x%X\n",
177
module, chan,
178
(uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
179
(*fpPrint)
180
("Module %d: Channel %d Dest Stats Addr 0x%X\n",
181
module, chan,
182
(uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
183
(*fpPrint)
184
("Module %d: Channel %d Config (LO) 0x%X\n",
185
module, chan,
186
(uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
187
(*fpPrint)
188
("Module %d: Channel %d Config (HI) 0x%X\n",
189
module, chan,
190
(uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
191
}
192
} else {
193
chan = channel;
194
(*fpPrint)
195
("--------------------------------------------------\n");
196
(*fpPrint)
197
("Module %d: Channel %d Source 0x%X\n",
198
module, chan, (uint32_t) (dmacHw_REG_SAR(module, chan)));
199
(*fpPrint)
200
("Module %d: Channel %d Destination 0x%X\n",
201
module, chan, (uint32_t) (dmacHw_REG_DAR(module, chan)));
202
(*fpPrint)
203
("Module %d: Channel %d LLP 0x%X\n",
204
module, chan, (uint32_t) (dmacHw_REG_LLP(module, chan)));
205
(*fpPrint)
206
("Module %d: Channel %d Control (LO) 0x%X\n",
207
module, chan,
208
(uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
209
(*fpPrint)
210
("Module %d: Channel %d Control (HI) 0x%X\n",
211
module, chan,
212
(uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
213
(*fpPrint)
214
("Module %d: Channel %d Source Stats 0x%X\n",
215
module, chan, (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
216
(*fpPrint)
217
("Module %d: Channel %d Dest Stats 0x%X\n",
218
module, chan, (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
219
(*fpPrint)
220
("Module %d: Channel %d Source Stats Addr 0x%X\n",
221
module, chan,
222
(uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
223
(*fpPrint)
224
("Module %d: Channel %d Dest Stats Addr 0x%X\n",
225
module, chan,
226
(uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
227
(*fpPrint)
228
("Module %d: Channel %d Config (LO) 0x%X\n",
229
module, chan,
230
(uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
231
(*fpPrint)
232
("Module %d: Channel %d Config (HI) 0x%X\n",
233
module, chan,
234
(uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
235
}
236
}
237
238
/****************************************************************************/
239
/**
240
* @brief Helper function to display descriptor ring
241
*
242
* @return void
243
*
244
*
245
* @note
246
* None
247
*/
248
/****************************************************************************/
249
static void DisplayDescRing(void *pDescriptor, /* [ IN ] Descriptor buffer */
250
int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
251
) {
252
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
253
dmacHw_DESC_t *pStart;
254
255
if (pRing->pHead == NULL) {
256
return;
257
}
258
259
pStart = pRing->pHead;
260
261
while ((dmacHw_DESC_t *) pStart->llp != pRing->pHead) {
262
if (pStart == pRing->pHead) {
263
(*fpPrint) ("Head\n");
264
}
265
if (pStart == pRing->pTail) {
266
(*fpPrint) ("Tail\n");
267
}
268
if (pStart == pRing->pProg) {
269
(*fpPrint) ("Prog\n");
270
}
271
if (pStart == pRing->pEnd) {
272
(*fpPrint) ("End\n");
273
}
274
if (pStart == pRing->pFree) {
275
(*fpPrint) ("Free\n");
276
}
277
(*fpPrint) ("0x%X:\n", (uint32_t) pStart);
278
(*fpPrint) ("sar 0x%0X\n", pStart->sar);
279
(*fpPrint) ("dar 0x%0X\n", pStart->dar);
280
(*fpPrint) ("llp 0x%0X\n", pStart->llp);
281
(*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
282
(*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
283
(*fpPrint) ("sstat 0x%0X\n", pStart->sstat);
284
(*fpPrint) ("dstat 0x%0X\n", pStart->dstat);
285
(*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
286
287
pStart = (dmacHw_DESC_t *) pStart->llp;
288
}
289
if (pStart == pRing->pHead) {
290
(*fpPrint) ("Head\n");
291
}
292
if (pStart == pRing->pTail) {
293
(*fpPrint) ("Tail\n");
294
}
295
if (pStart == pRing->pProg) {
296
(*fpPrint) ("Prog\n");
297
}
298
if (pStart == pRing->pEnd) {
299
(*fpPrint) ("End\n");
300
}
301
if (pStart == pRing->pFree) {
302
(*fpPrint) ("Free\n");
303
}
304
(*fpPrint) ("0x%X:\n", (uint32_t) pStart);
305
(*fpPrint) ("sar 0x%0X\n", pStart->sar);
306
(*fpPrint) ("dar 0x%0X\n", pStart->dar);
307
(*fpPrint) ("llp 0x%0X\n", pStart->llp);
308
(*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
309
(*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
310
(*fpPrint) ("sstat 0x%0X\n", pStart->sstat);
311
(*fpPrint) ("dstat 0x%0X\n", pStart->dstat);
312
(*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
313
}
314
315
/****************************************************************************/
316
/**
317
* @brief Check if DMA channel is the flow controller
318
*
319
* @return 1 : If DMA is a flow controller
320
* 0 : Peripheral is the flow controller
321
*
322
* @note
323
* None
324
*/
325
/****************************************************************************/
326
static inline int DmaIsFlowController(void *pDescriptor /* [ IN ] Descriptor buffer */
327
) {
328
uint32_t ttfc =
329
(dmacHw_GET_DESC_RING(pDescriptor))->pTail->ctl.
330
lo & dmacHw_REG_CTL_TTFC_MASK;
331
332
switch (ttfc) {
333
case dmacHw_REG_CTL_TTFC_MM_DMAC:
334
case dmacHw_REG_CTL_TTFC_MP_DMAC:
335
case dmacHw_REG_CTL_TTFC_PM_DMAC:
336
case dmacHw_REG_CTL_TTFC_PP_DMAC:
337
return 1;
338
}
339
340
return 0;
341
}
342
343
/****************************************************************************/
344
/**
345
* @brief Overwrites data length in the descriptor
346
*
347
* This function overwrites data length in the descriptor
348
*
349
*
350
* @return void
351
*
352
* @note
353
* This is only used for PCM channel
354
*/
355
/****************************************************************************/
356
void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
357
void *pDescriptor, /* [ IN ] Descriptor buffer */
358
size_t dataLen /* [ IN ] Data length in bytes */
359
) {
360
dmacHw_DESC_t *pProg;
361
dmacHw_DESC_t *pHead;
362
int srcTs = 0;
363
int srcTrSize = 0;
364
365
pHead = (dmacHw_GET_DESC_RING(pDescriptor))->pHead;
366
pProg = pHead;
367
368
srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
369
srcTs = dataLen / srcTrSize;
370
do {
371
pProg->ctl.hi = srcTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
372
pProg = (dmacHw_DESC_t *) pProg->llp;
373
} while (pProg != pHead);
374
}
375
376
/****************************************************************************/
377
/**
378
* @brief Clears the interrupt
379
*
380
* This function clears the DMA channel specific interrupt
381
*
382
*
383
* @return void
384
*
385
* @note
386
* Must be called under the context of ISR
387
*/
388
/****************************************************************************/
389
void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
390
) {
391
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
392
393
dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
394
dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
395
dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
396
}
397
398
/****************************************************************************/
399
/**
400
* @brief Returns the cause of channel specific DMA interrupt
401
*
402
* This function returns the cause of interrupt
403
*
404
* @return Interrupt status, each bit representing a specific type of interrupt
405
*
406
* @note
407
* Should be called under the context of ISR
408
*/
409
/****************************************************************************/
410
dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
411
) {
412
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
413
dmacHw_INTERRUPT_STATUS_e status = dmacHw_INTERRUPT_STATUS_NONE;
414
415
if (dmacHw_REG_INT_STAT_TRAN(pCblk->module) &
416
((0x00000001 << pCblk->channel))) {
417
status |= dmacHw_INTERRUPT_STATUS_TRANS;
418
}
419
if (dmacHw_REG_INT_STAT_BLOCK(pCblk->module) &
420
((0x00000001 << pCblk->channel))) {
421
status |= dmacHw_INTERRUPT_STATUS_BLOCK;
422
}
423
if (dmacHw_REG_INT_STAT_ERROR(pCblk->module) &
424
((0x00000001 << pCblk->channel))) {
425
status |= dmacHw_INTERRUPT_STATUS_ERROR;
426
}
427
428
return status;
429
}
430
431
/****************************************************************************/
432
/**
433
* @brief Indentifies a DMA channel causing interrupt
434
*
435
* This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
436
*
437
* @return NULL : No channel causing DMA interrupt
438
* ! NULL : Handle to a channel causing DMA interrupt
439
* @note
440
* dmacHw_clearInterrupt() must be called with a valid handle after calling this function
441
*/
442
/****************************************************************************/
443
dmacHw_HANDLE_t dmacHw_getInterruptSource(void)
444
{
445
uint32_t i;
446
447
for (i = 0; i < dmaChannelCount_0 + dmaChannelCount_1; i++) {
448
if ((dmacHw_REG_INT_STAT_TRAN(dmacHw_gCblk[i].module) &
449
((0x00000001 << dmacHw_gCblk[i].channel)))
450
|| (dmacHw_REG_INT_STAT_BLOCK(dmacHw_gCblk[i].module) &
451
((0x00000001 << dmacHw_gCblk[i].channel)))
452
|| (dmacHw_REG_INT_STAT_ERROR(dmacHw_gCblk[i].module) &
453
((0x00000001 << dmacHw_gCblk[i].channel)))
454
) {
455
return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[i]);
456
}
457
}
458
return dmacHw_CBLK_TO_HANDLE(NULL);
459
}
460
461
/****************************************************************************/
462
/**
463
* @brief Estimates number of descriptor needed to perform certain DMA transfer
464
*
465
*
466
* @return On failure : -1
467
* On success : Number of descriptor count
468
*
469
*
470
*/
471
/****************************************************************************/
472
int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
473
void *pSrcAddr, /* [ IN ] Source (Peripheral/Memory) address */
474
void *pDstAddr, /* [ IN ] Destination (Peripheral/Memory) address */
475
size_t dataLen /* [ IN ] Data length in bytes */
476
) {
477
int srcTs = 0;
478
int oddSize = 0;
479
int descCount = 0;
480
int dstTrSize = 0;
481
int srcTrSize = 0;
482
uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
483
dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
484
dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
485
486
dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
487
srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
488
489
/* Skip Tx if buffer is NULL or length is unknown */
490
if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
491
/* Do not initiate transfer */
492
return -1;
493
}
494
495
/* Ensure scatter and gather are transaction aligned */
496
if (pConfig->srcGatherWidth % srcTrSize
497
|| pConfig->dstScatterWidth % dstTrSize) {
498
return -1;
499
}
500
501
/*
502
Background 1: DMAC can not perform DMA if source and destination addresses are
503
not properly aligned with the channel's transaction width. So, for successful
504
DMA transfer, transaction width must be set according to the alignment of the
505
source and destination address.
506
*/
507
508
/* Adjust destination transaction width if destination address is not aligned properly */
509
dstTrWidth = pConfig->dstMaxTransactionWidth;
510
while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
511
dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
512
dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
513
}
514
515
/* Adjust source transaction width if source address is not aligned properly */
516
srcTrWidth = pConfig->srcMaxTransactionWidth;
517
while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
518
srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
519
srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
520
}
521
522
/* Find the maximum transaction per descriptor */
523
if (pConfig->maxDataPerBlock
524
&& ((pConfig->maxDataPerBlock / srcTrSize) <
525
dmacHw_MAX_BLOCKSIZE)) {
526
maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
527
}
528
529
/* Find number of source transactions needed to complete the DMA transfer */
530
srcTs = dataLen / srcTrSize;
531
/* Find the odd number of bytes that need to be transferred as single byte transaction width */
532
if (srcTs && (dstTrSize > srcTrSize)) {
533
oddSize = dataLen % dstTrSize;
534
/* Adjust source transaction count due to "oddSize" */
535
srcTs = srcTs - (oddSize / srcTrSize);
536
} else {
537
oddSize = dataLen % srcTrSize;
538
}
539
/* Adjust "descCount" due to "oddSize" */
540
if (oddSize) {
541
descCount++;
542
}
543
544
/* Find the number of descriptor needed for total "srcTs" */
545
if (srcTs) {
546
descCount += ((srcTs - 1) / maxBlockSize) + 1;
547
}
548
549
return descCount;
550
}
551
552
/****************************************************************************/
553
/**
554
* @brief Check the existence of pending descriptor
555
*
556
* This function confirmes if there is any pending descriptor in the chain
557
* to program the channel
558
*
559
* @return 1 : Channel need to be programmed with pending descriptor
560
* 0 : No more pending descriptor to programe the channel
561
*
562
* @note
563
* - This function should be called from ISR in case there are pending
564
* descriptor to program the channel.
565
*
566
* Example:
567
*
568
* dmac_isr ()
569
* {
570
* ...
571
* if (dmacHw_descriptorPending (handle))
572
* {
573
* dmacHw_initiateTransfer (handle);
574
* }
575
* }
576
*
577
*/
578
/****************************************************************************/
579
uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
580
void *pDescriptor /* [ IN ] Descriptor buffer */
581
) {
582
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
583
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
584
585
/* Make sure channel is not busy */
586
if (!CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
587
/* Check if pEnd is not processed */
588
if (pRing->pEnd) {
589
/* Something left for processing */
590
return 1;
591
}
592
}
593
return 0;
594
}
595
596
/****************************************************************************/
597
/**
598
* @brief Program channel register to stop transfer
599
*
600
* Ensures the channel is not doing any transfer after calling this function
601
*
602
* @return void
603
*
604
*/
605
/****************************************************************************/
606
void dmacHw_stopTransfer(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
607
) {
608
dmacHw_CBLK_t *pCblk;
609
610
pCblk = dmacHw_HANDLE_TO_CBLK(handle);
611
612
/* Stop the channel */
613
dmacHw_DMA_STOP(pCblk->module, pCblk->channel);
614
}
615
616
/****************************************************************************/
617
/**
618
* @brief Deallocates source or destination memory, allocated
619
*
620
* This function can be called to deallocate data memory that was DMAed successfully
621
*
622
* @return On failure : -1
623
* On success : Number of buffer freed
624
*
625
* @note
626
* This function will be called ONLY, when source OR destination address is pointing
627
* to dynamic memory
628
*/
629
/****************************************************************************/
630
int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
631
void *pDescriptor, /* [ IN ] Descriptor buffer */
632
void (*fpFree) (void *) /* [ IN ] Function pointer to free data memory */
633
) {
634
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
635
uint32_t count = 0;
636
637
if (fpFree == NULL) {
638
return -1;
639
}
640
641
while ((pRing->pFree != pRing->pTail)
642
&& (pRing->pFree->ctl.lo & dmacHw_DESC_FREE)) {
643
if (pRing->pFree->devCtl == dmacHw_FREE_USER_MEMORY) {
644
/* Identify, which memory to free */
645
if (dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
646
(*fpFree) ((void *)pRing->pFree->dar);
647
} else {
648
/* Destination was a peripheral */
649
(*fpFree) ((void *)pRing->pFree->sar);
650
}
651
/* Unmark user memory to indicate it is freed */
652
pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY;
653
}
654
dmacHw_NEXT_DESC(pRing, pFree);
655
656
count++;
657
}
658
659
return count;
660
}
661
662
/****************************************************************************/
663
/**
664
* @brief Prepares descriptor ring, when source peripheral working as a flow controller
665
*
666
* This function will update the discriptor ring by allocating buffers, when source peripheral
667
* has to work as a flow controller to transfer data from:
668
* - Peripheral to memory.
669
*
670
* @return On failure : -1
671
* On success : Number of descriptor updated
672
*
673
*
674
* @note
675
* Channel must be configured for peripheral to memory transfer
676
*
677
*/
678
/****************************************************************************/
679
int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
680
dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
681
void *pDescriptor, /* [ IN ] Descriptor buffer */
682
uint32_t srcAddr, /* [ IN ] Source peripheral address */
683
void *(*fpAlloc) (int len), /* [ IN ] Function pointer that provides destination memory */
684
int len, /* [ IN ] Number of bytes "fpAlloc" will allocate for destination */
685
int num /* [ IN ] Number of descriptor to set */
686
) {
687
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
688
dmacHw_DESC_t *pProg = NULL;
689
dmacHw_DESC_t *pLast = NULL;
690
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
691
uint32_t dstAddr;
692
uint32_t controlParam;
693
int i;
694
695
dmacHw_ASSERT(pConfig->transferType ==
696
dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM);
697
698
if (num > pRing->num) {
699
return -1;
700
}
701
702
pLast = pRing->pEnd; /* Last descriptor updated */
703
pProg = pRing->pHead; /* First descriptor in the new list */
704
705
controlParam = pConfig->srcUpdate |
706
pConfig->dstUpdate |
707
pConfig->srcMaxTransactionWidth |
708
pConfig->dstMaxTransactionWidth |
709
pConfig->srcMasterInterface |
710
pConfig->dstMasterInterface |
711
pConfig->srcMaxBurstWidth |
712
pConfig->dstMaxBurstWidth |
713
dmacHw_REG_CTL_TTFC_PM_PERI |
714
dmacHw_REG_CTL_LLP_DST_EN |
715
dmacHw_REG_CTL_LLP_SRC_EN | dmacHw_REG_CTL_INT_EN;
716
717
for (i = 0; i < num; i++) {
718
/* Allocate Rx buffer only for idle descriptor */
719
if (((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) ||
720
((dmacHw_DESC_t *) pRing->pHead->llp == pRing->pTail)
721
) {
722
/* Rx descriptor is not idle */
723
break;
724
}
725
/* Set source address */
726
pRing->pHead->sar = srcAddr;
727
if (fpAlloc) {
728
/* Allocate memory for buffer in descriptor */
729
dstAddr = (uint32_t) (*fpAlloc) (len);
730
/* Check the destination address */
731
if (dstAddr == 0) {
732
if (i == 0) {
733
/* Not a single descriptor is available */
734
return -1;
735
}
736
break;
737
}
738
/* Set destination address */
739
pRing->pHead->dar = dstAddr;
740
}
741
/* Set control information */
742
pRing->pHead->ctl.lo = controlParam;
743
/* Use "devCtl" to mark the memory that need to be freed later */
744
pRing->pHead->devCtl = dmacHw_FREE_USER_MEMORY;
745
/* Descriptor is now owned by the channel */
746
pRing->pHead->ctl.hi = 0;
747
/* Remember the descriptor last updated */
748
pRing->pEnd = pRing->pHead;
749
/* Update next descriptor */
750
dmacHw_NEXT_DESC(pRing, pHead);
751
}
752
753
/* Mark the end of the list */
754
pRing->pEnd->ctl.lo &=
755
~(dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN);
756
/* Connect the list */
757
if (pLast != pProg) {
758
pLast->ctl.lo |=
759
dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN;
760
}
761
/* Mark the descriptors are updated */
762
pCblk->descUpdated = 1;
763
if (!pCblk->varDataStarted) {
764
/* LLP must be pointing to the first descriptor */
765
dmacHw_SET_LLP(pCblk->module, pCblk->channel,
766
(uint32_t) pProg - pRing->virt2PhyOffset);
767
/* Channel, handling variable data started */
768
pCblk->varDataStarted = 1;
769
}
770
771
return i;
772
}
773
774
/****************************************************************************/
775
/**
776
* @brief Read data DMAed to memory
777
*
778
* This function will read data that has been DMAed to memory while transferring from:
779
* - Memory to memory
780
* - Peripheral to memory
781
*
782
* @param handle -
783
* @param ppBbuf -
784
* @param pLen -
785
*
786
* @return 0 - No more data is available to read
787
* 1 - More data might be available to read
788
*
789
*/
790
/****************************************************************************/
791
int dmacHw_readTransferredData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
792
dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
793
void *pDescriptor, /* [ IN ] Descriptor buffer */
794
void **ppBbuf, /* [ OUT ] Data received */
795
size_t *pLlen /* [ OUT ] Length of the data received */
796
) {
797
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
798
799
(void)handle;
800
801
if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) {
802
if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) ||
803
(pRing->pTail == pRing->pHead)
804
) {
805
/* No receive data available */
806
*ppBbuf = (char *)NULL;
807
*pLlen = 0;
808
809
return 0;
810
}
811
}
812
813
/* Return read buffer and length */
814
*ppBbuf = (char *)pRing->pTail->dar;
815
816
/* Extract length of the received data */
817
if (DmaIsFlowController(pDescriptor)) {
818
uint32_t srcTrSize = 0;
819
820
switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) {
821
case dmacHw_REG_CTL_SRC_TR_WIDTH_8:
822
srcTrSize = 1;
823
break;
824
case dmacHw_REG_CTL_SRC_TR_WIDTH_16:
825
srcTrSize = 2;
826
break;
827
case dmacHw_REG_CTL_SRC_TR_WIDTH_32:
828
srcTrSize = 4;
829
break;
830
case dmacHw_REG_CTL_SRC_TR_WIDTH_64:
831
srcTrSize = 8;
832
break;
833
default:
834
dmacHw_ASSERT(0);
835
}
836
/* Calculate length from the block size */
837
*pLlen =
838
(pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) *
839
srcTrSize;
840
} else {
841
/* Extract length from the source peripheral */
842
*pLlen = pRing->pTail->sstat;
843
}
844
845
/* Advance tail to next descriptor */
846
dmacHw_NEXT_DESC(pRing, pTail);
847
848
return 1;
849
}
850
851
/****************************************************************************/
852
/**
853
* @brief Set descriptor carrying control information
854
*
855
* This function will be used to send specific control information to the device
856
* using the DMA channel
857
*
858
*
859
* @return -1 - On failure
860
* 0 - On success
861
*
862
* @note
863
* None
864
*/
865
/****************************************************************************/
866
int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
867
void *pDescriptor, /* [ IN ] Descriptor buffer */
868
uint32_t ctlAddress, /* [ IN ] Address of the device control register */
869
uint32_t control /* [ IN ] Device control information */
870
) {
871
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
872
873
if (ctlAddress == 0) {
874
return -1;
875
}
876
877
/* Check the availability of descriptors in the ring */
878
if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) {
879
return -1;
880
}
881
/* Set control information */
882
pRing->pHead->devCtl = control;
883
/* Set source and destination address */
884
pRing->pHead->sar = (uint32_t) &pRing->pHead->devCtl;
885
pRing->pHead->dar = ctlAddress;
886
/* Set control parameters */
887
if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
888
pRing->pHead->ctl.lo = pConfig->transferType |
889
dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
890
dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
891
dmacHw_SRC_TRANSACTION_WIDTH_32 |
892
pConfig->dstMaxTransactionWidth |
893
dmacHw_SRC_BURST_WIDTH_0 |
894
dmacHw_DST_BURST_WIDTH_0 |
895
pConfig->srcMasterInterface |
896
pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
897
} else {
898
uint32_t transferType = 0;
899
switch (pConfig->transferType) {
900
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
901
transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
902
break;
903
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
904
transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
905
break;
906
default:
907
dmacHw_ASSERT(0);
908
}
909
pRing->pHead->ctl.lo = transferType |
910
dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
911
dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
912
dmacHw_SRC_TRANSACTION_WIDTH_32 |
913
pConfig->dstMaxTransactionWidth |
914
dmacHw_SRC_BURST_WIDTH_0 |
915
dmacHw_DST_BURST_WIDTH_0 |
916
pConfig->srcMasterInterface |
917
pConfig->dstMasterInterface |
918
pConfig->flowControler | dmacHw_REG_CTL_INT_EN;
919
}
920
921
/* Set block transaction size to one 32 bit transaction */
922
pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1;
923
924
/* Remember the descriptor to initialize the registers */
925
if (pRing->pProg == dmacHw_DESC_INIT) {
926
pRing->pProg = pRing->pHead;
927
}
928
pRing->pEnd = pRing->pHead;
929
930
/* Advance the descriptor */
931
dmacHw_NEXT_DESC(pRing, pHead);
932
933
/* Update Tail pointer if destination is a peripheral */
934
if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
935
pRing->pTail = pRing->pHead;
936
}
937
return 0;
938
}
939
940
/****************************************************************************/
941
/**
942
* @brief Sets channel specific user data
943
*
944
* This function associates user data to a specific DMA channel
945
*
946
*/
947
/****************************************************************************/
948
void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
949
void *userData /* [ IN ] User data */
950
) {
951
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
952
953
pCblk->userData = userData;
954
}
955
956
/****************************************************************************/
957
/**
958
* @brief Gets channel specific user data
959
*
960
* This function returns user data specific to a DMA channel
961
*
962
* @return user data
963
*/
964
/****************************************************************************/
965
void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
966
) {
967
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
968
969
return pCblk->userData;
970
}
971
972
/****************************************************************************/
973
/**
974
* @brief Resets descriptor control information
975
*
976
* @return void
977
*/
978
/****************************************************************************/
979
void dmacHw_resetDescriptorControl(void *pDescriptor /* [ IN ] Descriptor buffer */
980
) {
981
int i;
982
dmacHw_DESC_RING_t *pRing;
983
dmacHw_DESC_t *pDesc;
984
985
pRing = dmacHw_GET_DESC_RING(pDescriptor);
986
pDesc = pRing->pHead;
987
988
for (i = 0; i < pRing->num; i++) {
989
/* Mark descriptor is ready to use */
990
pDesc->ctl.hi = dmacHw_DESC_FREE;
991
/* Look into next link list item */
992
pDesc++;
993
}
994
pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
995
pRing->pProg = dmacHw_DESC_INIT;
996
}
997
998
/****************************************************************************/
999
/**
1000
* @brief Displays channel specific registers and other control parameters
1001
*
1002
* @return void
1003
*
1004
*
1005
* @note
1006
* None
1007
*/
1008
/****************************************************************************/
1009
void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
1010
void *pDescriptor, /* [ IN ] Descriptor buffer */
1011
int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */
1012
) {
1013
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
1014
1015
DisplayRegisterContents(pCblk->module, pCblk->channel, fpPrint);
1016
DisplayDescRing(pDescriptor, fpPrint);
1017
}
1018
1019