dmacHw.c 28 KB

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