ck_dmac.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /******************************************************************************
  17. * @file ck_dmac.c
  18. * @brief CSI Source File for DMAC Driver
  19. * @version V1.0
  20. * @date 02. June 2017
  21. ******************************************************************************/
  22. #include <stdbool.h>
  23. #include "ck_dmac.h"
  24. #include "csi_core.h"
  25. #include "drv_dmac.h"
  26. #include "soc.h"
  27. #define ERR_DMA(errno) (CSI_DRV_ERRNO_DMA_BASE | errno)
  28. typedef struct {
  29. uint32_t base;
  30. uint32_t irq;
  31. dma_event_cb_t cb_event;
  32. uint8_t ch_num;
  33. } ck_dma_priv_t;
  34. static ck_dma_priv_t dma_instance[CONFIG_DMAC_NUM];
  35. static const dma_capabilities_t dma_capabilities = {
  36. .unalign_addr = 1, ///< support for unalign address transfer when memory is source
  37. };
  38. static volatile dma_status_e status[CK_DMA_MAXCHANNEL] = {DMA_STATE_FREE, DMA_STATE_FREE};
  39. static volatile uint8_t ch_opened[CK_DMA_MAXCHANNEL] = {0, 0};
  40. static int32_t ck_dma_set_channel(ck_dma_reg_t *addr, uint32_t source, uint32_t dest, uint32_t size)
  41. {
  42. uint32_t temp = addr->CHCTRLA;
  43. temp &= 0xff000fff;
  44. temp |= (size << 12);
  45. addr->SAR = source;
  46. addr->DAR = dest ;
  47. addr->CHCTRLA = temp;
  48. return 0;
  49. }
  50. static int32_t ck_dma_set_transfertype(ck_dma_reg_t *addr, dma_trans_type_e transtype)
  51. {
  52. uint32_t temp = addr->CHCTRLB;
  53. temp &= 0xffffff7f;
  54. if (transtype >= DMA_PERH2PERH) {
  55. return ERR_DMA(EDRV_PARAMETER);
  56. }
  57. if (transtype == DMA_MEM2MEM) {
  58. temp |= (transtype << 7);
  59. } else {
  60. temp |= (1 << 7);
  61. }
  62. addr->CHCTRLB = temp;
  63. return 0;
  64. }
  65. static int32_t ck_dma_set_addrinc(ck_dma_reg_t *addr, enum_addr_state_e src_addrinc, enum_addr_state_e dst_addrinc)
  66. {
  67. if ((src_addrinc != DMA_ADDR_INCREMENT && src_addrinc != DMA_ADDR_DECREMENT && src_addrinc != DMA_ADDR_NOCHANGE) ||
  68. (dst_addrinc != DMA_ADDR_INCREMENT && dst_addrinc != DMA_ADDR_DECREMENT && dst_addrinc != DMA_ADDR_NOCHANGE)) {
  69. return ERR_DMA(EDRV_PARAMETER);
  70. }
  71. uint32_t temp = addr->CHCTRLA;
  72. temp &= 0xffffff0f;
  73. temp |= (src_addrinc << 6);
  74. temp |= (dst_addrinc << 4);
  75. addr->CHCTRLA = temp;
  76. return 0;
  77. }
  78. static int32_t ck_dma_set_transferwidth(ck_dma_reg_t *addr, dma_datawidth_e src_width, dma_datawidth_e dst_width)
  79. {
  80. if ((src_width != DMA_DATAWIDTH_SIZE8 && src_width != DMA_DATAWIDTH_SIZE16 && src_width != DMA_DATAWIDTH_SIZE32) ||
  81. (dst_width != DMA_DATAWIDTH_SIZE8 && dst_width != DMA_DATAWIDTH_SIZE16 && dst_width != DMA_DATAWIDTH_SIZE32)) {
  82. return ERR_DMA(EDRV_PARAMETER);
  83. }
  84. uint32_t temp = addr->CHCTRLA;
  85. temp &= 0xfffffff0;
  86. temp |= (src_width - 1) << 2;
  87. temp |= dst_width - 1;
  88. addr->CHCTRLA = temp;
  89. return 0;
  90. }
  91. static int32_t ck_dma_set_burstlength(ck_dma_reg_t *addr, uint8_t burstlength)
  92. {
  93. uint32_t temp = addr->CHCTRLA;
  94. temp &= 0xfffff0ff;
  95. temp |= (burstlength << 8);
  96. addr->CHCTRLA = temp;
  97. return 0;
  98. }
  99. /**
  100. \brief Set software or hardware handshaking.
  101. \param[in] addr pointer to dma register.
  102. \return error code
  103. */
  104. static int32_t ck_dma_set_handshaking(ck_dma_reg_t *addr, dma_handshaking_select_e handshaking)
  105. {
  106. uint32_t temp = addr->CHCTRLB;
  107. temp &= 0xfffffeff;
  108. temp |= (handshaking << 8);
  109. addr->CHCTRLB = temp;
  110. return 0;
  111. }
  112. static int ck_dma_assign_hdhs_interface(ck_dma_reg_t *addr, ckenum_dma_device_e device)
  113. {
  114. if (device < 0 || device >= CKENUM_DMA_MEMORY) {
  115. return ERR_DMA(EDRV_PARAMETER);
  116. }
  117. addr->CHCTRLB &= 0xffffe1ff;
  118. addr->CHCTRLB |= (device << 9);
  119. return 0;
  120. }
  121. void ck_dma_irqhandler(int32_t idx)
  122. {
  123. ck_dma_priv_t *dma_priv = &dma_instance[idx];
  124. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base);
  125. /*
  126. * StatusInt_temp contain the information that which types of interrupr are
  127. * requested.
  128. */
  129. int32_t count = 0;
  130. uint32_t temp = 0;
  131. for (count = 0; count < dma_priv->ch_num; count++) {
  132. addr = (ck_dma_reg_t *)(dma_priv->base + count * 0x30);
  133. temp = addr->CHINTS;
  134. if (temp != 0) {
  135. break;
  136. }
  137. }
  138. /* If Tfr interrupt is requested */
  139. if (temp == CK_DMA_TFR) {
  140. status[count] = DMA_STATE_DONE;
  141. addr->CHINTC = temp;
  142. if (dma_priv->cb_event) {
  143. dma_priv->cb_event(DMA_EVENT_TRANSFER_DONE, count);
  144. }
  145. }
  146. /* If Err interrput is requested */
  147. if (temp == CK_DMA_ERR) {
  148. status[count] = DMA_STATE_ERROR;
  149. addr->CHINTC = temp;
  150. if (dma_priv->cb_event) {
  151. dma_priv->cb_event(DMA_EVENT_TRANSFER_ERROR, count);
  152. }
  153. }
  154. }
  155. int32_t __attribute__((weak)) target_get_dmac_count(void)
  156. {
  157. return 0;
  158. }
  159. int32_t __attribute__((weak)) target_get_dmac(uint32_t idx, uint32_t *base, uint32_t *irq)
  160. {
  161. return NULL;
  162. }
  163. /**
  164. \brief get dma instance count.
  165. \return dma instance count
  166. */
  167. int32_t csi_dma_get_instance_count(void)
  168. {
  169. return target_get_dmac_count();
  170. }
  171. /**
  172. \brief Initialize DMA Interface. 1. Initializes the resources needed for the DMA interface 2.registers event callback function
  173. \param[in] idx must not exceed return value of csi_dma_get_instance_count()
  174. \return pointer to dma instances
  175. */
  176. dmac_handle_t csi_dma_initialize(int32_t idx)
  177. {
  178. if (idx < 0 || idx >= CONFIG_DMAC_NUM) {
  179. return NULL;
  180. }
  181. uint32_t base = 0u;
  182. uint32_t irq = 0u;
  183. int32_t real_idx = target_get_dmac(idx, &base, &irq);
  184. if (real_idx != idx) {
  185. return NULL;
  186. }
  187. ck_dma_priv_t *dma_priv = &dma_instance[idx];
  188. dma_priv->base = base;
  189. dma_priv->irq = irq;
  190. dma_priv->ch_num = CK_DMA_MAXCHANNEL;
  191. drv_nvic_enable_irq(dma_priv->irq);
  192. uint8_t count = 0u;
  193. for (count = 0; count < dma_priv->ch_num; count++) {
  194. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base + count * 0x30);
  195. addr->CHINTM = CK_DMA_MASK;
  196. addr->CHINTC = CK_DMA_INTC;
  197. }
  198. return (dmac_handle_t)dma_priv;
  199. }
  200. /**
  201. \brief De-initialize DMA Interface. stops operation and releases the software resources used by the interface
  202. \param[in] handle damc handle to operate.
  203. \return error code
  204. */
  205. int32_t csi_dma_uninitialize(dmac_handle_t handle)
  206. {
  207. if (handle == NULL) {
  208. return ERR_DMA(EDRV_PARAMETER);
  209. }
  210. ck_dma_priv_t *dma_priv = handle;
  211. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base);
  212. uint8_t count;
  213. for (count = 0; count < dma_priv->ch_num; count++) {
  214. addr = (ck_dma_reg_t *)(dma_priv->base + count * 0x30);
  215. addr->CHINTM = CK_DMA_MASK;
  216. addr->CHINTC = CK_DMA_INTC;
  217. }
  218. drv_nvic_disable_irq(dma_priv->irq);
  219. return 0;
  220. }
  221. /**
  222. \brief Get driver capabilities.
  223. \param[in] handle damc handle to operate.
  224. \return \ref dma_capabilities_t
  225. */
  226. dma_capabilities_t csi_dma_get_capabilities(dmac_handle_t handle)
  227. {
  228. return dma_capabilities;
  229. }
  230. /**
  231. \brief get one free dma channel
  232. \param[in] handle damc handle to operate.
  233. \param[in] ch channel num. if -1 then allocate a free channal in this dma
  234. \return -1 - no channel can be used, other - channel index
  235. */
  236. int32_t csi_dma_alloc_channel(dmac_handle_t handle, int32_t ch)
  237. {
  238. ck_dma_priv_t *dma_priv = handle;
  239. if (handle == NULL || ch > dma_priv->ch_num) {
  240. return ERR_DMA(EDRV_PARAMETER);
  241. }
  242. uint8_t ch_num = 0;
  243. ck_dma_reg_t *addr = NULL;
  244. if (ch == -1) { // alloc a free channal
  245. for (ch_num = 0; ch_num < dma_priv->ch_num; ch_num++) {
  246. addr = (ck_dma_reg_t *)(dma_priv->base + ch_num * 0x30);
  247. if (ch_opened[ch_num] != 0x1) {
  248. ch_opened[ch_num] = 1;
  249. break;
  250. }
  251. }
  252. if (ch_num >= dma_priv->ch_num) {
  253. return -1;
  254. }
  255. } else { //alloc a fixed channel
  256. addr = (ck_dma_reg_t *)(dma_priv->base + ch * 0x30);
  257. if (ch_opened[ch] == 0x1) {
  258. return ERR_DMA(EDRV_BUSY);
  259. }
  260. ch_opened[ch] = 1;
  261. ch_num = ch;
  262. }
  263. addr->CHINTC = CK_DMA_INTC;
  264. addr->CHINTM &= ~CK_DMA_MASK;
  265. status[ch_num] = DMA_STATE_READY;
  266. return ch_num;
  267. }
  268. /**
  269. \brief release dma channel and related resources
  270. \param[in] handle damc handle to operate.
  271. \param[in] ch channel num.
  272. \return error code
  273. */
  274. int32_t csi_dma_release_channel(dmac_handle_t handle, int32_t ch)
  275. {
  276. ck_dma_priv_t *dma_priv = handle;
  277. if (handle == NULL || ch >= dma_priv->ch_num || ch < 0) {
  278. return ERR_DMA(EDRV_PARAMETER);
  279. }
  280. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base + ch * 0x30);
  281. status[ch] = DMA_STATE_FREE;
  282. ch_opened[ch] = 0;
  283. addr->CHINTC = CK_DMA_INTC;
  284. addr->CHINTM = CK_DMA_MASK;
  285. return 0;
  286. }
  287. /**
  288. \brief
  289. \param[in] handle damc handle to operate.
  290. \param[in] ch channel num. if -1 then allocate a free channal in this dma
  291. \param[in] psrcaddr dma transfer source address
  292. \param[in] pstdaddr dma transfer source address
  293. \param[in] length dma transfer length
  294. \param[in] config dma transfer configure
  295. \param[in] cb_event Pointer to \ref dma_event_cb_t
  296. \return error code
  297. */
  298. int32_t csi_dma_config(dmac_handle_t handle, int32_t ch,
  299. void *psrcaddr, void *pstdaddr,
  300. uint32_t length, dma_config_t *config, dma_event_cb_t cb_event)
  301. {
  302. ck_dma_priv_t *dma_priv = handle;
  303. if (handle == NULL || ch >= dma_priv->ch_num || config == NULL) {
  304. return ERR_DMA(EDRV_PARAMETER);
  305. }
  306. if (ch == -1) { //alloc a free channel
  307. ch = csi_dma_alloc_channel(handle, -1);
  308. if (ch < 0) {
  309. return ERR_DMA(EDRV_BUSY);
  310. }
  311. }
  312. dma_priv->cb_event = cb_event;
  313. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base + ch * 0x30);
  314. /* Initializes corresponding channel registers */
  315. if ((length * config->src_tw) % config->dst_tw != 0) {
  316. return ERR_DMA(EDRV_PARAMETER);
  317. }
  318. int32_t ret = ck_dma_set_transferwidth(addr, config->src_tw, config->dst_tw);
  319. if (ret) {
  320. return ret;
  321. }
  322. int32_t grouplen = ((length * config->src_tw / config->dst_tw) - 1) % 16;
  323. ck_dma_set_burstlength(addr, grouplen);
  324. ret = ck_dma_set_transfertype(addr, config->type);
  325. if (ret < 0) {
  326. return ret;
  327. }
  328. if (config->type == DMA_MEM2MEM) {
  329. ck_dma_set_handshaking(addr, DMA_HANDSHAKING_SOFTWARE);
  330. ret = ck_dma_set_addrinc(addr , config->src_inc, config->dst_inc);
  331. } else if (config->type == DMA_MEM2PERH) {
  332. ck_dma_set_handshaking(addr, DMA_HANDSHAKING_HARDWARE);
  333. ret = ck_dma_set_addrinc(addr , config->src_inc, config->dst_inc);
  334. if (ret) {
  335. return ret;
  336. }
  337. ret = ck_dma_assign_hdhs_interface(addr, config->hs_if);
  338. if (ret) {
  339. return ret;
  340. }
  341. } else if (config->type == DMA_PERH2MEM) {
  342. ck_dma_set_handshaking(addr, DMA_HANDSHAKING_HARDWARE);
  343. ret = ck_dma_set_addrinc(addr , config->src_inc, config->dst_inc);
  344. if (ret) {
  345. return ret;
  346. }
  347. ret = ck_dma_assign_hdhs_interface(addr, config->hs_if);
  348. if (ret) {
  349. return ret;
  350. }
  351. }
  352. ck_dma_set_channel(addr, (uint32_t)psrcaddr, (uint32_t)pstdaddr, length);
  353. status[ch] = DMA_STATE_READY;
  354. return 0;
  355. }
  356. /**
  357. \brief start generate dma signal.
  358. \param[in] handle damc handle to operate.
  359. \param[in] ch channel num.
  360. \return error code
  361. */
  362. int32_t csi_dma_start(dmac_handle_t handle, int32_t ch)
  363. {
  364. ck_dma_priv_t *dma_priv = handle;
  365. if (handle == NULL || ch >= dma_priv->ch_num || ch < 0) {
  366. return ERR_DMA(EDRV_PARAMETER);
  367. }
  368. status[ch] = DMA_STATE_BUSY;
  369. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base + ch * 0x30);
  370. addr->CHCTRLB |= CK_DMA_INT_EN; // interrupt enable
  371. addr->CHEN |= CK_DMA_CH_EN;
  372. return 0;
  373. }
  374. /**
  375. \brief Stop generate dma signal.
  376. \param[in] handle damc handle to operate.
  377. \param[in] ch channel num.
  378. \return error code
  379. */
  380. int32_t csi_dma_stop(dmac_handle_t handle, int32_t ch)
  381. {
  382. if (handle == NULL) {
  383. return ERR_DMA(EDRV_PARAMETER);
  384. }
  385. ck_dma_priv_t *dma_priv = handle;
  386. if (ch >= dma_priv->ch_num || ch < 0) {
  387. return ERR_DMA(EDRV_PARAMETER);
  388. }
  389. status[ch] = DMA_STATE_DONE;
  390. ck_dma_reg_t *addr = (ck_dma_reg_t *)(dma_priv->base + ch * 0x30);
  391. addr->CHCTRLB &= ~CK_DMA_INT_EN; // interrupt disable
  392. addr->CHEN &= ~CK_DMA_CH_EN;
  393. return 0;
  394. }
  395. /**
  396. \brief Get DMA status.
  397. \param[in] handle damc handle to operate.
  398. \param[in] ch channel num.
  399. \return DMA status \ref dma_status_t
  400. */
  401. dma_status_e csi_dma_get_status(dmac_handle_t handle, int32_t ch)
  402. {
  403. if (handle == NULL) {
  404. return ERR_DMA(EDRV_PARAMETER);
  405. }
  406. ck_dma_priv_t *dma_priv = handle;
  407. if (ch >= dma_priv->ch_num || ch < 0) {
  408. return ERR_DMA(EDRV_PARAMETER);
  409. }
  410. return status[ch];
  411. }