fddma.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * Copyright : (C) 2022 Phytium Information Technology, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is OPEN SOURCE software: you can redistribute it and/or modify it
  6. * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
  7. * either version 1.0 of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  10. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the Phytium Public License for more details.
  12. *
  13. *
  14. * FilePath: fddma.c
  15. * Date: 2022-02-10 14:53:42
  16. * LastEditTime: 2022-02-18 08:24:47
  17. * Description:  This files is for ddma interface implementation
  18. *
  19. * Modify History:
  20. * Ver   Who        Date         Changes
  21. * ----- ------     --------    --------------------------------------
  22. * 1.0 Zhugengyu 2022/5/13 init commit
  23. */
  24. /***************************** Include Files *********************************/
  25. #include <string.h>
  26. #include "fkernel.h"
  27. #include "fparameters.h"
  28. #include "fassert.h"
  29. #include "fdebug.h"
  30. #include "fddma_hw.h"
  31. #include "fddma.h"
  32. /************************** Constant Definitions *****************************/
  33. /**************************** Type Definitions *******************************/
  34. /************************** Variable Definitions *****************************/
  35. /***************** Macros (Inline Functions) Definitions *********************/
  36. #define FDDMA_DEBUG_TAG "DDMA"
  37. #define FDDMA_ERROR(format, ...) FT_DEBUG_PRINT_E(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
  38. #define FDDMA_WARN(format, ...) FT_DEBUG_PRINT_W(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
  39. #define FDDMA_INFO(format, ...) FT_DEBUG_PRINT_I(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
  40. #define FDDMA_DEBUG(format, ...) FT_DEBUG_PRINT_D(FDDMA_DEBUG_TAG, format, ##__VA_ARGS__)
  41. /************************** Function Prototypes ******************************/
  42. static FError FDdmaReset(FDdma *const instance);
  43. /****************************************************************************/
  44. /**
  45. * @name: FDdmaCfgInitialization
  46. * @msg: 初始化DDMA控制器
  47. * @return {FError} FDDMA_SUCCESS表示初始化成功,其它返回值表示初始化失败
  48. * @param {FDdma} *instance, DDMA控制器实例
  49. * @param {FDdmaConfig} *input_config, DDMA控制器配置
  50. */
  51. FError FDdmaCfgInitialization(FDdma *const instance, const FDdmaConfig *input_config)
  52. {
  53. FASSERT(instance && input_config);
  54. uintptr base_addr = input_config->base_addr;
  55. FError ret = FDDMA_SUCCESS;
  56. if (FT_COMPONENT_IS_READY == instance->is_ready)
  57. {
  58. FDDMA_WARN("device is already initialized!!!");
  59. }
  60. FDdmaDeInitialization(instance);
  61. instance->config = *input_config;
  62. ret = FDdmaReset(instance);
  63. if (FDDMA_SUCCESS == ret)
  64. {
  65. instance->is_ready = FT_COMPONENT_IS_READY;
  66. FDDMA_INFO("ddma@0x%x init success !!!", base_addr);
  67. }
  68. return ret;
  69. }
  70. /**
  71. * @name: FDdmaStart
  72. * @msg: 启动DDMA控制器,开始传输
  73. * @return {FError} FDDMA_SUCCESS表示启动成功,其它返回值表示启动失败
  74. * @param {FDdma} *instance, DDMA控制器实例
  75. */
  76. FError FDdmaStart(FDdma *const instance)
  77. {
  78. FASSERT(instance);
  79. FError ret = FDDMA_SUCCESS;
  80. uintptr base_addr = instance->config.base_addr;
  81. if (FT_COMPONENT_IS_READY != instance->is_ready)
  82. {
  83. FDDMA_ERROR("dma instance not init !!!");
  84. return FDDMA_ERR_NOT_INIT;
  85. }
  86. FDdmaEnableGlobalIrq(base_addr); /* enable ddma irq */
  87. FDdmaEnable(base_addr);
  88. return FDDMA_SUCCESS;
  89. }
  90. /**
  91. * @name: FDdmaStop
  92. * @msg: 停止DDMA控制器
  93. * @return {FError} FDDMA_SUCCESS表示停止成功,其它返回值表示停止失败
  94. * @param {FDdma} *instance, DDMA控制器实例
  95. */
  96. FError FDdmaStop(FDdma *const instance)
  97. {
  98. FASSERT(instance);
  99. FError ret = FDDMA_SUCCESS;
  100. uintptr base_addr = instance->config.base_addr;
  101. if (FT_COMPONENT_IS_READY != instance->is_ready)
  102. {
  103. FDDMA_ERROR("dma instance not init !!!");
  104. return FDDMA_ERR_NOT_INIT;
  105. }
  106. FDdmaDisableGlobalIrq(base_addr); /* enable ddma irq */
  107. FDdmaDisable(base_addr);
  108. return FDDMA_SUCCESS;
  109. }
  110. /**
  111. * @name: FDdmaDeInitialization
  112. * @msg: 去初始化DDMA控制器
  113. * @return {无}
  114. * @param {FDdma} *instance, DDMA控制器实例
  115. */
  116. void FDdmaDeInitialization(FDdma *const instance)
  117. {
  118. FASSERT(instance);
  119. u32 chan;
  120. for (chan = 0; chan < FDDMA_NUM_OF_CHAN; chan++)
  121. {
  122. if (instance->bind_status & BIT(chan))
  123. {
  124. FDDMA_WARN("channel %d has not been unbind", chan);
  125. }
  126. }
  127. memset(instance, 0, sizeof(*instance));
  128. return;
  129. }
  130. /**
  131. * @name: FDdmaAllocateChan
  132. * @msg: 按照配置分配DDMA通道
  133. * @return {FError} FDDMA_SUCCESS表示分配成功,其它返回值表示分配失败
  134. * @param {FDdma} *instance, DDMA控制器实例
  135. * @param {FDdmaChan} *dma_chan, DDMA通道实例
  136. * @param {FDdmaChanConfig} *dma_chan_config, DDMA通道配置
  137. */
  138. FError FDdmaAllocateChan(FDdma *const instance, FDdmaChan *const dma_chan, const FDdmaChanConfig *dma_chan_config)
  139. {
  140. FASSERT(instance && dma_chan && dma_chan_config);
  141. FError ret = FDDMA_SUCCESS;
  142. const FDdmaChanIndex chan_idx = dma_chan_config->id;
  143. u32 reg_val;
  144. uintptr base_addr = instance->config.base_addr;
  145. if (FT_COMPONENT_IS_READY != instance->is_ready)
  146. {
  147. FDDMA_ERROR("dma instance not init !!!");
  148. return FDDMA_ERR_NOT_INIT;
  149. }
  150. if ((TRUE == dma_chan->is_used) || (BIT(chan_idx) & instance->bind_status))
  151. {
  152. FDDMA_ERROR("chan-%d is already is use !!!", chan_idx);
  153. return FDDMA_ERR_CHAN_BINDED;
  154. }
  155. if (FDdmaIsChanRunning(base_addr, chan_idx))
  156. {
  157. FDDMA_ERROR("chan-%d is already running !!!", chan_idx);
  158. return FDDMA_ERR_CHAN_BINDED;
  159. }
  160. if (dma_chan_config->ddr_addr % FDDMA_DDR_ADDR_ALIGMENT)
  161. {
  162. FDDMA_ERROR("ddr addr 0x%x must align with %d bytes",
  163. dma_chan_config->ddr_addr, FDDMA_DDR_ADDR_ALIGMENT);
  164. return FDDMA_ERR_INVALID_DDR_ADDR;
  165. }
  166. if ((FDDMA_MAX_TRANSFER_LEN < dma_chan_config->trans_len) ||
  167. (FDDMA_MIN_TRANSFER_LEN > dma_chan_config->trans_len) ||
  168. (0 != dma_chan_config->trans_len % FDDMA_MIN_TRANSFER_LEN))
  169. {
  170. FDDMA_ERROR("invalid transfer size %d Bytes !!!", dma_chan_config->trans_len);
  171. return FDDMA_ERR_INVALID_TRANS_SIZE;
  172. }
  173. dma_chan->dma = instance;
  174. instance->chan[chan_idx] = dma_chan;
  175. if (&(dma_chan->config) != dma_chan_config)
  176. dma_chan->config = *dma_chan_config;
  177. FDdmaStop(instance); /* disable irq */
  178. if (FDDMA_SUCCESS != FDdmaDisableChan(base_addr, chan_idx))
  179. {
  180. FDDMA_ERROR("disable DDMA@0x%x channel %d failed !!!", base_addr, chan_idx);
  181. return FDDMA_ERR_WAIT_TIMEOUT;
  182. }
  183. FDdmaResetChan(base_addr, chan_idx); /* reset channel */
  184. FDdmaSetChanSelection(base_addr, chan_idx, dma_chan->config.slave_id); /* select channel */
  185. FDdmaSetChanBind(base_addr, chan_idx, TRUE); /* bind channel */
  186. /* setup transfer src and dst */
  187. /* dma_tx_req: ddr --> dev 从内存中读取数据,写入外设 */
  188. /* dma_rx_req: dev --> ddr 从外设读取数据到内存 */
  189. #ifdef __aarch64___
  190. FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx), LOWER_32_BITS(dma_chan_config->ddr_addr));
  191. FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_UP_ADDR_OFFSET(chan_idx), UPPER_32_BITS(dma_chan_config->ddr_addr));
  192. #else
  193. FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx), (u32)(dma_chan_config->ddr_addr));
  194. FDdmaWriteReg(base_addr, FDDMA_CHAN_DDR_UP_ADDR_OFFSET(chan_idx), 0);
  195. #endif
  196. FDdmaWriteReg(base_addr, FDDMA_CHAN_DEV_ADDR_OFFSET(chan_idx), dma_chan_config->dev_addr);
  197. FDdmaWriteReg(base_addr, FDDMA_CHAN_TS_OFFSET(chan_idx), dma_chan_config->trans_len); /* block size */
  198. /* set channel request direction */
  199. FDdmaSetChanDirection(base_addr, chan_idx,
  200. (FDDMA_CHAN_REQ_RX == dma_chan->config.req_mode) ? TRUE : FALSE);
  201. FDDMA_INFO("chan-%d ddr @0x%x", chan_idx, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx));
  202. FDDMA_INFO("ddr addr: 0x%x", FDdmaReadReg(base_addr, FDDMA_CHAN_DDR_LOW_ADDR_OFFSET(chan_idx)));
  203. FDDMA_INFO("dev addr: 0x%x", FDdmaReadReg(base_addr, FDDMA_CHAN_DEV_ADDR_OFFSET(chan_idx)));
  204. FDDMA_INFO("trans len: %d", FDdmaReadReg(base_addr, FDDMA_CHAN_TS_OFFSET(chan_idx)));
  205. FDdmaSetChanTimeout(base_addr, chan_idx, 0xffff);
  206. FDdmaEnableChanIrq(base_addr, chan_idx);
  207. if (FDDMA_SUCCESS == ret)
  208. {
  209. instance->bind_status |= BIT(chan_idx);
  210. dma_chan->is_used = TRUE;
  211. FDDMA_INFO("allocate channel %d", chan_idx);
  212. }
  213. return ret;
  214. }
  215. /**
  216. * @name: FDdmaDellocateChan
  217. * @msg: 释放之前分配的DDMA通道
  218. * @return {FError} FDDMA_SUCCESS表示释放成功,其它返回值表示释放失败
  219. * @param {FDdmaChan} *dma_chan, DDMA控制器实例
  220. */
  221. FError FDdmaDellocateChan(FDdmaChan *const dma_chan)
  222. {
  223. FASSERT(dma_chan && dma_chan->dma);
  224. FDdma *const instance = dma_chan->dma;
  225. const FDdmaChanIndex chan_idx = dma_chan->config.id;
  226. uintptr base_addr = instance->config.base_addr;
  227. FError ret = FDDMA_SUCCESS;
  228. if (FT_COMPONENT_IS_READY != instance->is_ready)
  229. {
  230. FDDMA_ERROR("dma instance not init !!!");
  231. return FDDMA_ERR_NOT_INIT;
  232. }
  233. if (FDDMA_SUCCESS != FDdmaDisableChan(base_addr, chan_idx))
  234. {
  235. FDDMA_ERROR("disable DDMA@0x%x channel %d failed !!!", base_addr, chan_idx);
  236. return FDDMA_ERR_WAIT_TIMEOUT;
  237. }
  238. FDdmaResetChan(base_addr, chan_idx);
  239. FDdmaSetChanBind(base_addr, chan_idx, FALSE); /* unbind channel */
  240. ret = FDdmaDisableChan(base_addr, chan_idx);
  241. if (FDDMA_SUCCESS != ret) /* disable channel */
  242. {
  243. FDDMA_ERROR("disable ddma@%p channel %d failed !!!", base_addr, chan_idx);
  244. return ret;
  245. }
  246. FDdmaDisableChanIrq(base_addr, chan_idx); /* disable channel irq */
  247. instance->bind_status &= ~BIT(chan_idx); /* set bind status */
  248. instance->chan[chan_idx] = NULL;
  249. FDDMA_INFO("deallocate channel %d", chan_idx);
  250. memset(dma_chan, 0, sizeof(*dma_chan));
  251. return ret;
  252. }
  253. /**
  254. * @name: FDdmaActiveChan
  255. * @msg: 使能指定的DDMA通道
  256. * @note: 调用FDdmaAllocateChan后无需调用此函数
  257. * @return {FError} 返回FDDMA_SUCCESS表示成功,返回其它表示失败
  258. * @param FDdmaChan *const dma_chan, DDMA通道实例
  259. */
  260. FError FDdmaActiveChan(FDdmaChan *const dma_chan)
  261. {
  262. FASSERT(dma_chan && dma_chan->dma);
  263. FDdma *const instance = dma_chan->dma;
  264. uintptr base_addr = instance->config.base_addr;
  265. if (FT_COMPONENT_IS_READY != instance->is_ready)
  266. {
  267. FDDMA_ERROR("dma instance not init !!!");
  268. return FDDMA_ERR_NOT_INIT;
  269. }
  270. FDdmaEnableChan(base_addr, dma_chan->config.id);
  271. FDdmaClearChanIrq(base_addr, dma_chan->config.id); /* clear interrupt status */
  272. return FDDMA_SUCCESS;
  273. }
  274. FError FDdmaDeactiveChan(FDdmaChan *const dma_chan)
  275. {
  276. FASSERT(dma_chan && dma_chan->dma);
  277. FDdma *const instance = dma_chan->dma;
  278. uintptr base_addr = instance->config.base_addr;
  279. if (FT_COMPONENT_IS_READY != instance->is_ready)
  280. {
  281. FDDMA_ERROR("dma instance not init !!!");
  282. return FDDMA_ERR_NOT_INIT;
  283. }
  284. return FDdmaDisableChan(base_addr, dma_chan->config.id);
  285. }
  286. /**
  287. * @name: FDdmaReset
  288. * @msg: 重置DDMA控制器
  289. * @return {FError} FDDMA_SUCCESS表示重置成功,其它返回值表示失败
  290. * @param {FDdma} *instance, DDMA控制器实例
  291. */
  292. static FError FDdmaReset(FDdma *const instance)
  293. {
  294. FASSERT(instance);
  295. uintptr base_addr = instance->config.base_addr;
  296. FError ret = FDDMA_SUCCESS;
  297. u32 reg_val;
  298. u32 chan;
  299. if (0 != instance->bind_status)
  300. {
  301. FDDMA_WARN("some channel not yet un-bind !!!");
  302. }
  303. FDdmaDisable(base_addr); /* disable ddma */
  304. FDdmaSoftwareReset(base_addr); /* do software reset */
  305. FDdmaDisableGlobalIrq(base_addr);
  306. /* disable channel and its irq */
  307. for (u32 chan = FDDMA_CHAN_0; chan < FDDMA_NUM_OF_CHAN; chan++)
  308. {
  309. /* disable channel */
  310. ret = FDdmaDisableChan(base_addr, chan);
  311. if (FDDMA_SUCCESS != ret)
  312. {
  313. FDDMA_ERROR("disable ddma@%p channel %d failed !!!", base_addr, chan);
  314. break;
  315. }
  316. }
  317. FDdmaDumpRegisters(base_addr);
  318. return ret;
  319. }