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.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.c
18
*
19
* @brief 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
#include <csp/stdint.h>
29
#include <csp/string.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
#include <mach/csp/chipcHw_inline.h>
36
37
/* ---- External Function Prototypes ------------------------------------- */
38
39
/* Allocate DMA control blocks */
40
dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];
41
42
uint32_t dmaChannelCount_0 = dmacHw_MAX_CHANNEL_COUNT / 2;
43
uint32_t dmaChannelCount_1 = dmacHw_MAX_CHANNEL_COUNT / 2;
44
45
/****************************************************************************/
46
/**
47
* @brief Get maximum FIFO for a DMA channel
48
*
49
* @return Maximum allowable FIFO size
50
*
51
*
52
*/
53
/****************************************************************************/
54
static uint32_t GetFifoSize(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
55
) {
56
uint32_t val = 0;
57
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
58
dmacHw_MISC_t *pMiscReg =
59
(dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
60
61
switch (pCblk->channel) {
62
case 0:
63
val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
64
break;
65
case 1:
66
val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
67
break;
68
case 2:
69
val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
70
break;
71
case 3:
72
val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
73
break;
74
case 4:
75
val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
76
break;
77
case 5:
78
val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
79
break;
80
case 6:
81
val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
82
break;
83
case 7:
84
val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
85
break;
86
}
87
88
if (val <= 0x4) {
89
return 8 << val;
90
} else {
91
dmacHw_ASSERT(0);
92
}
93
return 0;
94
}
95
96
/****************************************************************************/
97
/**
98
* @brief Program channel register to initiate transfer
99
*
100
* @return void
101
*
102
*
103
* @note
104
* - Descriptor buffer MUST ALWAYS be flushed before calling this function
105
* - This function should also be called from ISR to program the channel with
106
* pending descriptors
107
*/
108
/****************************************************************************/
109
void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
110
dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
111
void *pDescriptor /* [ IN ] Descriptor buffer */
112
) {
113
dmacHw_DESC_RING_t *pRing;
114
dmacHw_DESC_t *pProg;
115
dmacHw_CBLK_t *pCblk;
116
117
pCblk = dmacHw_HANDLE_TO_CBLK(handle);
118
pRing = dmacHw_GET_DESC_RING(pDescriptor);
119
120
if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
121
/* Not safe yet to program the channel */
122
return;
123
}
124
125
if (pCblk->varDataStarted) {
126
if (pCblk->descUpdated) {
127
pCblk->descUpdated = 0;
128
pProg =
129
(dmacHw_DESC_t *) ((uint32_t)
130
dmacHw_REG_LLP(pCblk->module,
131
pCblk->channel) +
132
pRing->virt2PhyOffset);
133
134
/* Load descriptor if not loaded */
135
if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) {
136
dmacHw_SET_SAR(pCblk->module, pCblk->channel,
137
pProg->sar);
138
dmacHw_SET_DAR(pCblk->module, pCblk->channel,
139
pProg->dar);
140
dmacHw_REG_CTL_LO(pCblk->module,
141
pCblk->channel) =
142
pProg->ctl.lo;
143
dmacHw_REG_CTL_HI(pCblk->module,
144
pCblk->channel) =
145
pProg->ctl.hi;
146
} else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) {
147
/* Return as end descriptor is processed */
148
return;
149
} else {
150
dmacHw_ASSERT(0);
151
}
152
} else {
153
return;
154
}
155
} else {
156
if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) {
157
/* Do not make a single chain, rather process one descriptor at a time */
158
pProg = pRing->pHead;
159
/* Point to the next descriptor for next iteration */
160
dmacHw_NEXT_DESC(pRing, pHead);
161
} else {
162
/* Return if no more pending descriptor */
163
if (pRing->pEnd == NULL) {
164
return;
165
}
166
167
pProg = pRing->pProg;
168
if (pConfig->transferMode ==
169
dmacHw_TRANSFER_MODE_CONTINUOUS) {
170
/* Make sure a complete ring can be formed */
171
dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd->
172
llp == pRing->pProg);
173
/* Make sure pProg pointing to the pHead */
174
dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg ==
175
pRing->pHead);
176
/* Make a complete ring */
177
do {
178
pRing->pProg->ctl.lo |=
179
(dmacHw_REG_CTL_LLP_DST_EN |
180
dmacHw_REG_CTL_LLP_SRC_EN);
181
pRing->pProg =
182
(dmacHw_DESC_t *) pRing->pProg->llp;
183
} while (pRing->pProg != pRing->pHead);
184
} else {
185
/* Make a single long chain */
186
while (pRing->pProg != pRing->pEnd) {
187
pRing->pProg->ctl.lo |=
188
(dmacHw_REG_CTL_LLP_DST_EN |
189
dmacHw_REG_CTL_LLP_SRC_EN);
190
pRing->pProg =
191
(dmacHw_DESC_t *) pRing->pProg->llp;
192
}
193
}
194
}
195
196
/* Program the channel registers */
197
dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar);
198
dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar);
199
dmacHw_SET_LLP(pCblk->module, pCblk->channel,
200
(uint32_t) pProg - pRing->virt2PhyOffset);
201
dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) =
202
pProg->ctl.lo;
203
dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) =
204
pProg->ctl.hi;
205
if (pRing->pEnd) {
206
/* Remember the descriptor to use next */
207
pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp;
208
}
209
/* Indicate no more pending descriptor */
210
pRing->pEnd = (dmacHw_DESC_t *) NULL;
211
}
212
/* Start DMA operation */
213
dmacHw_DMA_START(pCblk->module, pCblk->channel);
214
}
215
216
/****************************************************************************/
217
/**
218
* @brief Initializes DMA
219
*
220
* This function initializes DMA CSP driver
221
*
222
* @note
223
* Must be called before using any DMA channel
224
*/
225
/****************************************************************************/
226
void dmacHw_initDma(void)
227
{
228
229
uint32_t i = 0;
230
231
dmaChannelCount_0 = dmacHw_GET_NUM_CHANNEL(0);
232
dmaChannelCount_1 = dmacHw_GET_NUM_CHANNEL(1);
233
234
/* Enable access to the DMA block */
235
chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC0);
236
chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC1);
237
238
if ((dmaChannelCount_0 + dmaChannelCount_1) > dmacHw_MAX_CHANNEL_COUNT) {
239
dmacHw_ASSERT(0);
240
}
241
242
memset((void *)dmacHw_gCblk, 0,
243
sizeof(dmacHw_CBLK_t) * (dmaChannelCount_0 + dmaChannelCount_1));
244
for (i = 0; i < dmaChannelCount_0; i++) {
245
dmacHw_gCblk[i].module = 0;
246
dmacHw_gCblk[i].channel = i;
247
}
248
for (i = 0; i < dmaChannelCount_1; i++) {
249
dmacHw_gCblk[i + dmaChannelCount_0].module = 1;
250
dmacHw_gCblk[i + dmaChannelCount_0].channel = i;
251
}
252
}
253
254
/****************************************************************************/
255
/**
256
* @brief Exit function for DMA
257
*
258
* This function isolates DMA from the system
259
*
260
*/
261
/****************************************************************************/
262
void dmacHw_exitDma(void)
263
{
264
/* Disable access to the DMA block */
265
chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC0);
266
chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC1);
267
}
268
269
/****************************************************************************/
270
/**
271
* @brief Gets a handle to a DMA channel
272
*
273
* This function returns a handle, representing a control block of a particular DMA channel
274
*
275
* @return -1 - On Failure
276
* handle - On Success, representing a channel control block
277
*
278
* @note
279
* None Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
280
*/
281
/****************************************************************************/
282
dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId /* [ IN ] DMA Channel Id */
283
) {
284
int idx;
285
286
switch ((channelId >> 8)) {
287
case 0:
288
dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_0);
289
idx = (channelId & 0xff);
290
break;
291
case 1:
292
dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_1);
293
idx = dmaChannelCount_0 + (channelId & 0xff);
294
break;
295
default:
296
dmacHw_ASSERT(0);
297
return (dmacHw_HANDLE_t) -1;
298
}
299
300
return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[idx]);
301
}
302
303
/****************************************************************************/
304
/**
305
* @brief Initializes a DMA channel for use
306
*
307
* This function initializes and resets a DMA channel for use
308
*
309
* @return -1 - On Failure
310
* 0 - On Success
311
*
312
* @note
313
* None
314
*/
315
/****************************************************************************/
316
int dmacHw_initChannel(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
317
) {
318
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
319
int module = pCblk->module;
320
int channel = pCblk->channel;
321
322
/* Reinitialize the control block */
323
memset((void *)pCblk, 0, sizeof(dmacHw_CBLK_t));
324
pCblk->module = module;
325
pCblk->channel = channel;
326
327
/* Enable DMA controller */
328
dmacHw_DMA_ENABLE(pCblk->module);
329
/* Reset DMA channel */
330
dmacHw_RESET_CONTROL_LO(pCblk->module, pCblk->channel);
331
dmacHw_RESET_CONTROL_HI(pCblk->module, pCblk->channel);
332
dmacHw_RESET_CONFIG_LO(pCblk->module, pCblk->channel);
333
dmacHw_RESET_CONFIG_HI(pCblk->module, pCblk->channel);
334
335
/* Clear all raw interrupt status */
336
dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
337
dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
338
dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
339
340
/* Mask event specific interrupts */
341
dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
342
dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
343
dmacHw_STRAN_INT_DISABLE(pCblk->module, pCblk->channel);
344
dmacHw_DTRAN_INT_DISABLE(pCblk->module, pCblk->channel);
345
dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
346
347
return 0;
348
}
349
350
/****************************************************************************/
351
/**
352
* @brief Finds amount of memory required to form a descriptor ring
353
*
354
*
355
* @return Number of bytes required to form a descriptor ring
356
*
357
*
358
*/
359
/****************************************************************************/
360
uint32_t dmacHw_descriptorLen(uint32_t descCnt /* [ IN ] Number of descriptor in the ring */
361
) {
362
/* Need extra 4 byte to ensure 32 bit alignment */
363
return (descCnt * sizeof(dmacHw_DESC_t)) + sizeof(dmacHw_DESC_RING_t) +
364
sizeof(uint32_t);
365
}
366
367
/****************************************************************************/
368
/**
369
* @brief Initializes descriptor ring
370
*
371
* This function will initializes the descriptor ring of a DMA channel
372
*
373
*
374
* @return -1 - On failure
375
* 0 - On success
376
* @note
377
* - "len" parameter should be obtained from "dmacHw_descriptorLen"
378
* - Descriptor buffer MUST be 32 bit aligned and uncached as it is
379
* accessed by ARM and DMA
380
*/
381
/****************************************************************************/
382
int dmacHw_initDescriptor(void *pDescriptorVirt, /* [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
383
uint32_t descriptorPhyAddr, /* [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
384
uint32_t len, /* [ IN ] Size of the pBuf */
385
uint32_t num /* [ IN ] Number of descriptor in the ring */
386
) {
387
uint32_t i;
388
dmacHw_DESC_RING_t *pRing;
389
dmacHw_DESC_t *pDesc;
390
391
/* Check the alignment of the descriptor */
392
if ((uint32_t) pDescriptorVirt & 0x00000003) {
393
dmacHw_ASSERT(0);
394
return -1;
395
}
396
397
/* Check if enough space has been allocated for descriptor ring */
398
if (len < dmacHw_descriptorLen(num)) {
399
return -1;
400
}
401
402
pRing = dmacHw_GET_DESC_RING(pDescriptorVirt);
403
pRing->pHead =
404
(dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t));
405
pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
406
pRing->pProg = dmacHw_DESC_INIT;
407
/* Initialize link item chain, starting from the head */
408
pDesc = pRing->pHead;
409
/* Find the offset between virtual to physical address */
410
pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr;
411
412
/* Form the descriptor ring */
413
for (i = 0; i < num - 1; i++) {
414
/* Clear link list item */
415
memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
416
/* Point to the next item in the physical address */
417
pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset;
418
/* Point to the next item in the virtual address */
419
pDesc->llp = (uint32_t) (pDesc + 1);
420
/* Mark descriptor is ready to use */
421
pDesc->ctl.hi = dmacHw_DESC_FREE;
422
/* Look into next link list item */
423
pDesc++;
424
}
425
426
/* Clear last link list item */
427
memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
428
/* Last item pointing to the first item in the
429
physical address to complete the ring */
430
pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset;
431
/* Last item pointing to the first item in the
432
virtual address to complete the ring
433
*/
434
pDesc->llp = (uint32_t) pRing->pHead;
435
/* Mark descriptor is ready to use */
436
pDesc->ctl.hi = dmacHw_DESC_FREE;
437
/* Set the number of descriptors in the ring */
438
pRing->num = num;
439
return 0;
440
}
441
442
/****************************************************************************/
443
/**
444
* @brief Configure DMA channel
445
*
446
* @return 0 : On success
447
* -1 : On failure
448
*/
449
/****************************************************************************/
450
int dmacHw_configChannel(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
451
dmacHw_CONFIG_t *pConfig /* [ IN ] Configuration settings */
452
) {
453
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
454
uint32_t cfgHigh = 0;
455
int srcTrSize;
456
int dstTrSize;
457
458
pCblk->varDataStarted = 0;
459
pCblk->userData = NULL;
460
461
/* Configure
462
- Burst transaction when enough data in available in FIFO
463
- AHB Access protection 1
464
- Source and destination peripheral ports
465
*/
466
cfgHigh =
467
dmacHw_REG_CFG_HI_FIFO_ENOUGH | dmacHw_REG_CFG_HI_AHB_HPROT_1 |
468
dmacHw_SRC_PERI_INTF(pConfig->
469
srcPeripheralPort) |
470
dmacHw_DST_PERI_INTF(pConfig->dstPeripheralPort);
471
/* Set priority */
472
dmacHw_SET_CHANNEL_PRIORITY(pCblk->module, pCblk->channel,
473
pConfig->channelPriority);
474
475
if (pConfig->dstStatusRegisterAddress != 0) {
476
/* Destination status update enable */
477
cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_DST_STAT;
478
/* Configure status registers */
479
dmacHw_SET_DSTATAR(pCblk->module, pCblk->channel,
480
pConfig->dstStatusRegisterAddress);
481
}
482
483
if (pConfig->srcStatusRegisterAddress != 0) {
484
/* Source status update enable */
485
cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_SRC_STAT;
486
/* Source status update enable */
487
dmacHw_SET_SSTATAR(pCblk->module, pCblk->channel,
488
pConfig->srcStatusRegisterAddress);
489
}
490
/* Configure the config high register */
491
dmacHw_GET_CONFIG_HI(pCblk->module, pCblk->channel) = cfgHigh;
492
493
/* Clear all raw interrupt status */
494
dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
495
dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
496
dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
497
498
/* Configure block interrupt */
499
if (pConfig->blockTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
500
dmacHw_BLOCK_INT_ENABLE(pCblk->module, pCblk->channel);
501
} else {
502
dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
503
}
504
/* Configure complete transfer interrupt */
505
if (pConfig->completeTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
506
dmacHw_TRAN_INT_ENABLE(pCblk->module, pCblk->channel);
507
} else {
508
dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
509
}
510
/* Configure error interrupt */
511
if (pConfig->errorInterrupt == dmacHw_INTERRUPT_ENABLE) {
512
dmacHw_ERROR_INT_ENABLE(pCblk->module, pCblk->channel);
513
} else {
514
dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
515
}
516
/* Configure gather register */
517
if (pConfig->srcGatherWidth) {
518
srcTrSize =
519
dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
520
if (!
521
((pConfig->srcGatherWidth % srcTrSize)
522
&& (pConfig->srcGatherJump % srcTrSize))) {
523
dmacHw_REG_SGR_LO(pCblk->module, pCblk->channel) =
524
((pConfig->srcGatherWidth /
525
srcTrSize) << 20) | (pConfig->srcGatherJump /
526
srcTrSize);
527
} else {
528
return -1;
529
}
530
}
531
/* Configure scatter register */
532
if (pConfig->dstScatterWidth) {
533
dstTrSize =
534
dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
535
if (!
536
((pConfig->dstScatterWidth % dstTrSize)
537
&& (pConfig->dstScatterJump % dstTrSize))) {
538
dmacHw_REG_DSR_LO(pCblk->module, pCblk->channel) =
539
((pConfig->dstScatterWidth /
540
dstTrSize) << 20) | (pConfig->dstScatterJump /
541
dstTrSize);
542
} else {
543
return -1;
544
}
545
}
546
return 0;
547
}
548
549
/****************************************************************************/
550
/**
551
* @brief Indicates whether DMA transfer is in progress or completed
552
*
553
* @return DMA transfer status
554
* dmacHw_TRANSFER_STATUS_BUSY: DMA Transfer ongoing
555
* dmacHw_TRANSFER_STATUS_DONE: DMA Transfer completed
556
* dmacHw_TRANSFER_STATUS_ERROR: DMA Transfer error
557
*
558
*/
559
/****************************************************************************/
560
dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
561
) {
562
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
563
564
if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
565
return dmacHw_TRANSFER_STATUS_BUSY;
566
} else if (dmacHw_REG_INT_RAW_ERROR(pCblk->module) &
567
(0x00000001 << pCblk->channel)) {
568
return dmacHw_TRANSFER_STATUS_ERROR;
569
}
570
571
return dmacHw_TRANSFER_STATUS_DONE;
572
}
573
574
/****************************************************************************/
575
/**
576
* @brief Set descriptors for known data length
577
*
578
* When DMA has to work as a flow controller, this function prepares the
579
* descriptor chain to transfer data
580
*
581
* from:
582
* - Memory to memory
583
* - Peripheral to memory
584
* - Memory to Peripheral
585
* - Peripheral to Peripheral
586
*
587
* @return -1 - On failure
588
* 0 - On success
589
*
590
*/
591
/****************************************************************************/
592
int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
593
void *pDescriptor, /* [ IN ] Descriptor buffer */
594
void *pSrcAddr, /* [ IN ] Source (Peripheral/Memory) address */
595
void *pDstAddr, /* [ IN ] Destination (Peripheral/Memory) address */
596
size_t dataLen /* [ IN ] Data length in bytes */
597
) {
598
dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
599
dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
600
dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
601
dmacHw_DESC_t *pStart;
602
dmacHw_DESC_t *pProg;
603
int srcTs = 0;
604
int blkTs = 0;
605
int oddSize = 0;
606
int descCount = 0;
607
int count = 0;
608
int dstTrSize = 0;
609
int srcTrSize = 0;
610
uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
611
612
dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
613
srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
614
615
/* Skip Tx if buffer is NULL or length is unknown */
616
if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
617
/* Do not initiate transfer */
618
return -1;
619
}
620
621
/* Ensure scatter and gather are transaction aligned */
622
if ((pConfig->srcGatherWidth % srcTrSize)
623
|| (pConfig->dstScatterWidth % dstTrSize)) {
624
return -2;
625
}
626
627
/*
628
Background 1: DMAC can not perform DMA if source and destination addresses are
629
not properly aligned with the channel's transaction width. So, for successful
630
DMA transfer, transaction width must be set according to the alignment of the
631
source and destination address.
632
*/
633
634
/* Adjust destination transaction width if destination address is not aligned properly */
635
dstTrWidth = pConfig->dstMaxTransactionWidth;
636
while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
637
dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
638
dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
639
}
640
641
/* Adjust source transaction width if source address is not aligned properly */
642
srcTrWidth = pConfig->srcMaxTransactionWidth;
643
while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
644
srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
645
srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
646
}
647
648
/* Find the maximum transaction per descriptor */
649
if (pConfig->maxDataPerBlock
650
&& ((pConfig->maxDataPerBlock / srcTrSize) <
651
dmacHw_MAX_BLOCKSIZE)) {
652
maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
653
}
654
655
/* Find number of source transactions needed to complete the DMA transfer */
656
srcTs = dataLen / srcTrSize;
657
/* Find the odd number of bytes that need to be transferred as single byte transaction width */
658
if (srcTs && (dstTrSize > srcTrSize)) {
659
oddSize = dataLen % dstTrSize;
660
/* Adjust source transaction count due to "oddSize" */
661
srcTs = srcTs - (oddSize / srcTrSize);
662
} else {
663
oddSize = dataLen % srcTrSize;
664
}
665
/* Adjust "descCount" due to "oddSize" */
666
if (oddSize) {
667
descCount++;
668
}
669
/* Find the number of descriptor needed for total "srcTs" */
670
if (srcTs) {
671
descCount += ((srcTs - 1) / maxBlockSize) + 1;
672
}
673
674
/* Check the availability of "descCount" discriptors in the ring */
675
pProg = pRing->pHead;
676
for (count = 0; (descCount <= pRing->num) && (count < descCount);
677
count++) {
678
if ((pProg->ctl.hi & dmacHw_DESC_FREE) == 0) {
679
/* Sufficient descriptors are not available */
680
return -3;
681
}
682
pProg = (dmacHw_DESC_t *) pProg->llp;
683
}
684
685
/* Remember the link list item to program the channel registers */
686
pStart = pProg = pRing->pHead;
687
/* Make a link list with "descCount(=count)" number of descriptors */
688
while (count) {
689
/* Reset channel control information */
690
pProg->ctl.lo = 0;
691
/* Enable source gather if configured */
692
if (pConfig->srcGatherWidth) {
693
pProg->ctl.lo |= dmacHw_REG_CTL_SG_ENABLE;
694
}
695
/* Enable destination scatter if configured */
696
if (pConfig->dstScatterWidth) {
697
pProg->ctl.lo |= dmacHw_REG_CTL_DS_ENABLE;
698
}
699
/* Set source and destination address */
700
pProg->sar = (uint32_t) pSrcAddr;
701
pProg->dar = (uint32_t) pDstAddr;
702
/* Use "devCtl" to mark that user memory need to be freed later if needed */
703
if (pProg == pRing->pHead) {
704
pProg->devCtl = dmacHw_FREE_USER_MEMORY;
705
} else {
706
pProg->devCtl = 0;
707
}
708
709
blkTs = srcTs;
710
711
/* Special treatmeant for last descriptor */
712
if (count == 1) {
713
/* Mark the last descriptor */
714
pProg->ctl.lo &=
715
~(dmacHw_REG_CTL_LLP_DST_EN |
716
dmacHw_REG_CTL_LLP_SRC_EN);
717
/* Treatment for odd data bytes */
718
if (oddSize) {
719
/* Adjust for single byte transaction width */
720
switch (pConfig->transferType) {
721
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
722
dstTrWidth =
723
dmacHw_DST_TRANSACTION_WIDTH_8;
724
blkTs =
725
(oddSize / srcTrSize) +
726
((oddSize % srcTrSize) ? 1 : 0);
727
break;
728
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
729
srcTrWidth =
730
dmacHw_SRC_TRANSACTION_WIDTH_8;
731
blkTs = oddSize;
732
break;
733
case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
734
srcTrWidth =
735
dmacHw_SRC_TRANSACTION_WIDTH_8;
736
dstTrWidth =
737
dmacHw_DST_TRANSACTION_WIDTH_8;
738
blkTs = oddSize;
739
break;
740
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
741
/* Do not adjust the transaction width */
742
break;
743
}
744
} else {
745
srcTs -= blkTs;
746
}
747
} else {
748
if (srcTs / maxBlockSize) {
749
blkTs = maxBlockSize;
750
}
751
/* Remaining source transactions for next iteration */
752
srcTs -= blkTs;
753
}
754
/* Must have a valid source transactions */
755
dmacHw_ASSERT(blkTs > 0);
756
/* Set control information */
757
if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
758
pProg->ctl.lo |= pConfig->transferType |
759
pConfig->srcUpdate |
760
pConfig->dstUpdate |
761
srcTrWidth |
762
dstTrWidth |
763
pConfig->srcMaxBurstWidth |
764
pConfig->dstMaxBurstWidth |
765
pConfig->srcMasterInterface |
766
pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
767
} else {
768
uint32_t transferType = 0;
769
switch (pConfig->transferType) {
770
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
771
transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
772
break;
773
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
774
transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
775
break;
776
default:
777
dmacHw_ASSERT(0);
778
}
779
pProg->ctl.lo |= transferType |
780
pConfig->srcUpdate |
781
pConfig->dstUpdate |
782
srcTrWidth |
783
dstTrWidth |
784
pConfig->srcMaxBurstWidth |
785
pConfig->dstMaxBurstWidth |
786
pConfig->srcMasterInterface |
787
pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
788
}
789
790
/* Set block transaction size */
791
pProg->ctl.hi = blkTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
792
/* Look for next descriptor */
793
if (count > 1) {
794
/* Point to the next descriptor */
795
pProg = (dmacHw_DESC_t *) pProg->llp;
796
797
/* Update source and destination address for next iteration */
798
switch (pConfig->transferType) {
799
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
800
if (pConfig->dstScatterWidth) {
801
pDstAddr =
802
(char *)pDstAddr +
803
blkTs * srcTrSize +
804
(((blkTs * srcTrSize) /
805
pConfig->dstScatterWidth) *
806
pConfig->dstScatterJump);
807
} else {
808
pDstAddr =
809
(char *)pDstAddr +
810
blkTs * srcTrSize;
811
}
812
break;
813
case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
814
if (pConfig->srcGatherWidth) {
815
pSrcAddr =
816
(char *)pDstAddr +
817
blkTs * srcTrSize +
818
(((blkTs * srcTrSize) /
819
pConfig->srcGatherWidth) *
820
pConfig->srcGatherJump);
821
} else {
822
pSrcAddr =
823
(char *)pSrcAddr +
824
blkTs * srcTrSize;
825
}
826
break;
827
case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
828
if (pConfig->dstScatterWidth) {
829
pDstAddr =
830
(char *)pDstAddr +
831
blkTs * srcTrSize +
832
(((blkTs * srcTrSize) /
833
pConfig->dstScatterWidth) *
834
pConfig->dstScatterJump);
835
} else {
836
pDstAddr =
837
(char *)pDstAddr +
838
blkTs * srcTrSize;
839
}
840
841
if (pConfig->srcGatherWidth) {
842
pSrcAddr =
843
(char *)pDstAddr +
844
blkTs * srcTrSize +
845
(((blkTs * srcTrSize) /
846
pConfig->srcGatherWidth) *
847
pConfig->srcGatherJump);
848
} else {
849
pSrcAddr =
850
(char *)pSrcAddr +
851
blkTs * srcTrSize;
852
}
853
break;
854
case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
855
/* Do not adjust the address */
856
break;
857
default:
858
dmacHw_ASSERT(0);
859
}
860
} else {
861
/* At the end of transfer "srcTs" must be zero */
862
dmacHw_ASSERT(srcTs == 0);
863
}
864
count--;
865
}
866
867
/* Remember the descriptor to initialize the registers */
868
if (pRing->pProg == dmacHw_DESC_INIT) {
869
pRing->pProg = pStart;
870
}
871
/* Indicate that the descriptor is updated */
872
pRing->pEnd = pProg;
873
/* Head pointing to the next descriptor */
874
pRing->pHead = (dmacHw_DESC_t *) pProg->llp;
875
/* Update Tail pointer if destination is a peripheral,
876
because no one is going to read from the pTail
877
*/
878
if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
879
pRing->pTail = pRing->pHead;
880
}
881
return 0;
882
}
883
884
/****************************************************************************/
885
/**
886
* @brief Provides DMA controller attributes
887
*
888
*
889
* @return DMA controller attributes
890
*
891
* @note
892
* None
893
*/
894
/****************************************************************************/
895
uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
896
dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controller attribute of type dmacHw_CONTROLLER_ATTRIB_e */
897
) {
898
dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
899
900
switch (attr) {
901
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM:
902
return dmacHw_GET_NUM_CHANNEL(pCblk->module);
903
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE:
904
return (1 <<
905
(dmacHw_GET_MAX_BLOCK_SIZE
906
(pCblk->module, pCblk->module) + 2)) - 8;
907
case dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM:
908
return dmacHw_GET_NUM_INTERFACE(pCblk->module);
909
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH:
910
return 32 << dmacHw_GET_CHANNEL_DATA_WIDTH(pCblk->module,
911
pCblk->channel);
912
case dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE:
913
return GetFifoSize(handle);
914
}
915
dmacHw_ASSERT(0);
916
return 0;
917
}
918
919