dma-pl330.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include <bitmap.h>
  14. #define DBG_TAG "dma.pl330"
  15. #define DBG_LVL DBG_INFO
  16. #include <rtdbg.h>
  17. #define _FIELD_READ(h, l, x) ((RT_GENMASK(h, l) & (x)) >> l)
  18. #define PL330_REG_DSR 0x000 /* DMA Manager Status Register */
  19. #define PL330_REG_DPC 0x004 /* DMA Program Counter Register */
  20. #define PL330_REG_INTEN 0x020 /* Interrupt Enable Register */
  21. #define PL330_REG_INT_EVENT_RIS 0x024 /* Event-Interrupt Raw Status Register */
  22. #define PL330_REG_INTMIS 0x028 /* Interrupt Status Register */
  23. #define PL330_REG_INTCLR 0x02c /* Interrupt Clear Register */
  24. #define PL330_REG_FSRD 0x030 /* Fault Status DMA Manager Register */
  25. #define PL330_REG_FSRC 0x034 /* Fault Status DMA Channel Register */
  26. #define PL330_REG_FTRD 0x038 /* Fault Type DMA Manager Register */
  27. #define PL330_REG_FTR(n) (0x040 + (n) * 0x4) /* Fault Type DMA Channel [n] */
  28. #define PL330_FT_UNDEF_INSTR RT_BIT(0)
  29. #define PL330_FT_OPERAND_INVALID RT_BIT(1)
  30. #define PL330_FT_DMAGO_ERR RT_BIT(4)
  31. #define PL330_FT_EVENT_ERR RT_BIT(5)
  32. #define PL330_FT_CH_PERIPH_ERR RT_BIT(6)
  33. #define PL330_FT_CH_RDWR_ERR RT_BIT(7)
  34. #define PL330_FT_ST_DATA_UNAVAILABLE RT_BIT(12)
  35. #define PL330_FT_FIFOEMPTY_ERR RT_BIT(13)
  36. #define PL330_FT_INSTR_FETCH_ERR RT_BIT(16)
  37. #define PL330_FT_DATA_WRITE_ERR RT_BIT(17)
  38. #define PL330_FT_DATA_READ_ERR RT_BIT(18)
  39. #define PL330_FT_DBG_INSTR RT_BIT(30)
  40. #define PL330_FT_LOCKUP_ERR RT_BIT(31)
  41. #define PL330_REG_CSR(n) (0x100 + (n) * 0x8) /* Channel [n] Status Register */
  42. #define PL330_CS_STOP 0x0
  43. #define PL330_CS_EXEC 0x1
  44. #define PL330_CS_CMISS 0x2
  45. #define PL330_CS_UPDTPC 0x3
  46. #define PL330_CS_WFE 0x4
  47. #define PL330_CS_ATBRR 0x5
  48. #define PL330_CS_QBUSY 0x6
  49. #define PL330_CS_WFP 0x7
  50. #define PL330_CS_KILL 0x8
  51. #define PL330_CS_CMPLT 0x9
  52. #define PL330_CS_FLTCMP 0xe
  53. #define PL330_CS_FAULT 0xf
  54. #define PL330_REG_CPC(n) (0x104 + (n) * 0x8) /* Channel [n] Program Counter Register */
  55. #define pl330_REG_SAR(n) (0x0400 + (n) * 0x20) /* Channel [n] Source Address Register */
  56. #define pl330_REG_DAR(n) (0x0404 + (n) * 0x20) /* Channel [n] Destination Address Register */
  57. #define pl330_REG_CCR(n) (0x0408 + (n) * 0x20) /* Channel [n] Channel Control Register */
  58. #define pl330_REG_LC0(n) (0x040c + (n) * 0x20) /* Channel [n] Loop Counter 0 Register */
  59. #define pl330_REG_LC1(n) (0x0410 + (n) * 0x20) /* Channel [n] Loop Counter 1 Register */
  60. #define PL330_REG_DBGSTATUS 0xd00 /* Debug Status Register */
  61. #define PL330_DBGSTATUS_IDLE 0
  62. #define PL330_DBGSTATUS_BUSY RT_BIT(0)
  63. #define PL330_REG_DBGCMD 0xd04 /* Debug Command Register */
  64. #define PL330_REG_DBGINST0 0xd08 /* Debug Instruction-0 Register */
  65. #define PL330_REG_DBGINST1 0xd0c /* Debug Instruction-1 Register */
  66. #define PL330_REG_CR(n) (0xe00 + (n) * 0x4) /* Configuration Register [n] */
  67. #define PL330_CR0_PERIPH_REQ_SET RT_BIT(0)
  68. #define PL330_CR0_MGR_NS_AT_RST(x) _FIELD_READ(2, 2, x)
  69. #define PL330_CR0_NUM_CHNLS(x) _FIELD_READ(6, 4, x)
  70. #define PL330_CR0_NUM_PERIPH(x) _FIELD_READ(16, 12, x)
  71. #define PL330_CR0_NUM_EVENTS(x) _FIELD_READ(21, 17, x)
  72. #define PL330_REG_CRD 0x0e14 /* Configuration Register */
  73. #define PL330_CRD_DATA_WIDTH(x) _FIELD_READ(2, 0, x)
  74. #define PL330_CRD_WR_CAP(x) _FIELD_READ(6, 4, x)
  75. #define PL330_CRD_WR_Q_DEP(x) _FIELD_READ(11, 8, x)
  76. #define PL330_CRD_RD_CAP(x) _FIELD_READ(14, 12, x)
  77. #define PL330_CRD_RD_Q_DEP(x) _FIELD_READ(19, 16, x)
  78. #define PL330_CRD_DATA_BUFFER_DEP(x) _FIELD_READ(29, 20, x)
  79. #define PL330_REG_WDT 0x0e80 /* DMA Watchdog Register */
  80. #define PL330_REG_PERIPH_ID 0x0fe0 /* Periph ID Register */
  81. #define PL330_PERIPH_REV(x) _FIELD_READ(23, 20, x)
  82. #define PL330_PERIPH_REV_R0P0 0
  83. #define PL330_PERIPH_REV_R1P0 1
  84. #define PL330_PERIPH_REV_R1P1 2
  85. #define PL330_CMD_DMAADDH 0x54
  86. #define PL330_CMD_DMAEND 0x00
  87. #define PL330_CMD_DMAFLUSHP 0x35
  88. #define PL330_CMD_DMAGO 0xa0
  89. #define PL330_CMD_DMALD 0x04
  90. #define PL330_CMD_DMALDP 0x25
  91. #define PL330_CMD_DMALP 0x20
  92. #define PL330_CMD_DMALPEND 0x28
  93. #define PL330_CMD_DMAKILL 0x01
  94. #define PL330_CMD_DMAMOV 0xbc
  95. #define PL330_CMD_DMANOP 0x18
  96. #define PL330_CMD_DMARMB 0x12
  97. #define PL330_CMD_DMASEV 0x34
  98. #define PL330_CMD_DMAST 0x08
  99. #define PL330_CMD_DMASTP 0x29
  100. #define PL330_CMD_DMASTZ 0x0c
  101. #define PL330_CMD_DMAWFE 0x36
  102. #define PL330_CMD_DMAWFP 0x30
  103. #define PL330_CMD_DMAWMB 0x13
  104. #define PL330_SIZE_DMAADDH 3
  105. #define PL330_SIZE_DMAEND 1
  106. #define PL330_SIZE_DMAFLUSHP 2
  107. #define PL330_SIZE_DMALD 1
  108. #define PL330_SIZE_DMALDP 2
  109. #define PL330_SIZE_DMALP 2
  110. #define PL330_SIZE_DMALPEND 2
  111. #define PL330_SIZE_DMAKILL 1
  112. #define PL330_SIZE_DMAMOV 6
  113. #define PL330_SIZE_DMANOP 1
  114. #define PL330_SIZE_DMARMB 1
  115. #define PL330_SIZE_DMASEV 2
  116. #define PL330_SIZE_DMAST 1
  117. #define PL330_SIZE_DMASTP 2
  118. #define PL330_SIZE_DMASTZ 1
  119. #define PL330_SIZE_DMAWFE 2
  120. #define PL330_SIZE_DMAWFP 2
  121. #define PL330_SIZE_DMAWMB 1
  122. #define PL330_SIZE_DMAGO 6
  123. #define PL330_DIR_SAR 0
  124. #define PL330_DIR_CCR 1
  125. #define PL330_DIR_DAR 2
  126. #define PL330_SRC_INC RT_BIT(0)
  127. #define PL330_SRC_BURST_SIZE_SHIFT 1
  128. #define PL330_SRC_BURST_LEN_SHIFT 4
  129. #define PL330_DST_INC RT_BIT(14)
  130. #define PL330_DST_BURST_SIZE_SHIFT 15
  131. #define PL330_DST_BURST_LEN_SHIFT 18
  132. #define PL330_COND_SINGLE 0
  133. #define PL330_COND_BURST 1
  134. #define PL330_COND_ALWAYS 2
  135. #define PL330_MICROCODE_SIZE 128
  136. #define AMBA_NR_IRQS 9
  137. struct pl330_chan
  138. {
  139. struct rt_dma_chan parent;
  140. rt_bool_t enabled;
  141. rt_size_t size;
  142. void *microcode;
  143. rt_size_t microcode_len;
  144. rt_ubase_t microcode_dma;
  145. rt_uint8_t microcode_raw[PL330_MICROCODE_SIZE + 4]; /* For align */
  146. };
  147. struct pl330
  148. {
  149. struct rt_dma_controller parent;
  150. void *regs;
  151. int irqs_nr;
  152. int irqs[AMBA_NR_IRQS];
  153. #define PL330_QUIRK_BROKEN_NO_FLUSHP RT_BIT(0)
  154. #define PL330_QUIRK_PERIPH_BURST RT_BIT(1)
  155. rt_uint32_t quirk;
  156. rt_uint32_t mode_ns;
  157. rt_uint32_t num_chan;
  158. rt_uint32_t num_peri;
  159. rt_uint32_t num_events;
  160. rt_uint32_t data_width;
  161. rt_uint32_t data_buffer_dep;
  162. rt_uint32_t ins;
  163. struct pl330_chan *chans;
  164. struct rt_clk *pclk;
  165. struct rt_reset_control *rstc;
  166. struct rt_reset_control *rstc_ocp;
  167. };
  168. #define raw_to_pl330(raw) rt_container_of(raw, struct pl330, parent)
  169. static void pl330_read_config(struct pl330 *pl330)
  170. {
  171. rt_uint32_t value;
  172. void *regs = pl330->regs;
  173. value = HWREG32(regs + PL330_REG_CR(0));
  174. pl330->mode_ns = !!PL330_CR0_NUM_EVENTS(value);
  175. pl330->num_chan = PL330_CR0_NUM_CHNLS(value) + 1;
  176. pl330->num_events = PL330_CR0_NUM_EVENTS(value) + 1;
  177. if (value & PL330_CR0_PERIPH_REQ_SET)
  178. {
  179. pl330->num_peri = PL330_CR0_NUM_PERIPH(value) + 1;
  180. }
  181. value = HWREG32(regs + PL330_REG_CRD);
  182. pl330->data_width = 8 * (1 << PL330_CRD_DATA_WIDTH(value));
  183. pl330->data_buffer_dep = PL330_CRD_DATA_BUFFER_DEP(value) + 1;
  184. pl330->ins = HWREG32(regs + PL330_REG_CR(3));
  185. }
  186. static rt_err_t pl330_ccr_config(struct rt_dma_slave_config *conf, rt_uint32_t *ccr)
  187. {
  188. *ccr = PL330_SRC_INC | PL330_DST_INC;
  189. *ccr |= conf->src_maxburst << PL330_SRC_BURST_LEN_SHIFT;
  190. *ccr |= conf->dst_maxburst << PL330_DST_BURST_LEN_SHIFT;
  191. switch (conf->src_addr_width)
  192. {
  193. case RT_DMA_SLAVE_BUSWIDTH_1_BYTE:
  194. *ccr |= 0 << PL330_SRC_BURST_SIZE_SHIFT;
  195. break;
  196. case RT_DMA_SLAVE_BUSWIDTH_2_BYTES:
  197. *ccr |= 1 << PL330_SRC_BURST_SIZE_SHIFT;
  198. break;
  199. case RT_DMA_SLAVE_BUSWIDTH_4_BYTES:
  200. *ccr |= 2 << PL330_SRC_BURST_SIZE_SHIFT;
  201. break;
  202. default:
  203. return -RT_EINVAL;
  204. }
  205. switch (conf->dst_addr_width)
  206. {
  207. case RT_DMA_SLAVE_BUSWIDTH_1_BYTE:
  208. *ccr |= 0 << PL330_DST_BURST_SIZE_SHIFT;
  209. break;
  210. case RT_DMA_SLAVE_BUSWIDTH_2_BYTES:
  211. *ccr |= 1 << PL330_DST_BURST_SIZE_SHIFT;
  212. break;
  213. case RT_DMA_SLAVE_BUSWIDTH_4_BYTES:
  214. *ccr |= 2 << PL330_DST_BURST_SIZE_SHIFT;
  215. break;
  216. default:
  217. return -RT_EINVAL;
  218. }
  219. return RT_EOK;
  220. }
  221. static int pl330_cmd_dmamov(rt_uint8_t *microcode, rt_uint8_t rd, rt_uint32_t imm)
  222. {
  223. /*
  224. * DMAMOV encoding
  225. * 15 4 3 2 1 10 ... 8 7 6 5 4 3 2 1 0
  226. * 0 0 0 0 0 |rd[2:0]|1 0 1 1 1 1 0 0
  227. *
  228. * 47 ... 16
  229. * imm[32:0]
  230. *
  231. * rd: b000 for SAR, b001 CCR, b010 DAR
  232. */
  233. *microcode++ = PL330_CMD_DMAMOV;
  234. *microcode++ = rd;
  235. *microcode++ = imm;
  236. *microcode++ = imm >> 8;
  237. *microcode++ = imm >> 16;
  238. *microcode++ = imm >> 24;
  239. LOG_D("DMAMOV %s, %#x", ((const char *const []){
  240. [PL330_DIR_SAR] = "SAR",
  241. [PL330_DIR_CCR] = "CCR",
  242. [PL330_DIR_DAR] = "DAR"
  243. })[rd], imm);
  244. return PL330_SIZE_DMAMOV;
  245. }
  246. static int pl330_cmd_dmald(rt_uint8_t *microcode, rt_uint32_t cond)
  247. {
  248. /*
  249. * DMALD encoding
  250. * 7 6 5 4 3 2 1 0
  251. * 0 0 0 0 0 1 bs x
  252. */
  253. *microcode = PL330_CMD_DMALD;
  254. if (cond == PL330_COND_SINGLE)
  255. {
  256. *microcode |= (0 << 1) | (1 << 0);
  257. }
  258. else if (cond == PL330_COND_BURST)
  259. {
  260. *microcode |= (1 << 1) | (1 << 0);
  261. }
  262. LOG_D("DMALD %c", ((char []){
  263. [PL330_COND_SINGLE] = 'S',
  264. [PL330_COND_BURST] = 'B',
  265. [PL330_COND_ALWAYS] = 'A'
  266. })[cond]);
  267. return PL330_SIZE_DMALD;
  268. }
  269. static int pl330_cmd_dmast(rt_uint8_t *microcode, rt_uint32_t cond)
  270. {
  271. /*
  272. * DMAST encoding
  273. * 7 6 5 4 3 2 1 0
  274. * 0 0 0 0 1 0 bs x
  275. */
  276. *microcode = PL330_CMD_DMAST;
  277. if (cond == PL330_COND_SINGLE)
  278. {
  279. *microcode |= (0 << 1) | (1 << 0);
  280. }
  281. else if (cond == PL330_COND_BURST)
  282. {
  283. *microcode |= (1 << 1) | (1 << 0);
  284. }
  285. LOG_D("DMAST %c", ((char []){
  286. [PL330_COND_SINGLE] = 'S',
  287. [PL330_COND_BURST] = 'B',
  288. [PL330_COND_ALWAYS] = 'A'
  289. })[cond]);
  290. return PL330_SIZE_DMAST;
  291. }
  292. static int pl330_cmd_dmalp(rt_uint8_t *microcode, rt_uint8_t lc, rt_uint16_t loops)
  293. {
  294. /*
  295. * DMALP encoding
  296. * 15 ... 8 7 6 5 4 3 2 1 0
  297. * | iter[7:0] |0 0 1 0 0 0 lc 0
  298. */
  299. *microcode++ = PL330_CMD_DMALP | ((lc & 1) << 1);
  300. *microcode |= loops - 1;
  301. LOG_D("DMALP %u (lc: %c)", loops - 1, lc ? '1' : '0');
  302. return PL330_SIZE_DMALP;
  303. }
  304. static int pl330_cmd_dmalpend(rt_uint8_t *microcode, rt_uint32_t cond,
  305. rt_bool_t forever, rt_uint32_t loop, rt_uint8_t bjump)
  306. {
  307. /*
  308. * DMALPEND encoding
  309. * 15 ... 8 7 6 5 4 3 2 1 0
  310. * | backward_jump[7:0] |0 0 1 nf 1 lc bs x
  311. */
  312. *microcode = PL330_CMD_DMALPEND;
  313. if (loop)
  314. {
  315. *microcode |= (1 << 2);
  316. }
  317. if (!forever)
  318. {
  319. *microcode |= (1 << 4);
  320. }
  321. if (cond == PL330_COND_SINGLE)
  322. {
  323. *microcode |= (0 << 1) | (1 << 0);
  324. }
  325. else if (cond == PL330_COND_BURST)
  326. {
  327. *microcode |= (1 << 1) | (1 << 0);
  328. }
  329. ++microcode;
  330. *microcode = bjump;
  331. LOG_D("DMALPEND %c (%sloop: %c bjump: %d)", ((char []){
  332. [PL330_COND_SINGLE] = 'S',
  333. [PL330_COND_BURST] = 'B',
  334. [PL330_COND_ALWAYS] = 'A'
  335. })[cond], forever ? "FE, " : "", loop ? 'Y' : 'N', bjump);
  336. return PL330_SIZE_DMALPEND;
  337. }
  338. static int pl330_cmd_dmasev(rt_uint8_t *microcode, int event)
  339. {
  340. *microcode++ = PL330_CMD_DMASEV;
  341. *microcode++ = (event & 0x1f) << 3;
  342. LOG_D("DMASEV %u", event & 0x1f);
  343. return PL330_SIZE_DMASEV;
  344. }
  345. static int pl330_cmd_dmaend(rt_uint8_t *microcode)
  346. {
  347. /*
  348. * DMAEND encoding:
  349. * 7 6 5 4 3 2 1 0
  350. * 0 0 0 0 0 0 0 0
  351. */
  352. *microcode = PL330_CMD_DMAEND;
  353. LOG_D("DMAEND");
  354. return PL330_SIZE_DMAEND;
  355. }
  356. static rt_uint32_t pl330_chan_id(struct pl330 *pl330, struct pl330_chan *pc)
  357. {
  358. return pc - pl330->chans;
  359. }
  360. static struct rt_dma_chan *pl330_dma_request_chan(struct rt_dma_controller *ctrl,
  361. struct rt_device *slave, void *fw_data)
  362. {
  363. int idx = -1;
  364. struct pl330_chan *pc;
  365. struct pl330 *pl330 = raw_to_pl330(ctrl);
  366. struct rt_ofw_cell_args *args = fw_data;
  367. if (args && (idx = args->args[0]) >= pl330->num_chan)
  368. {
  369. return rt_err_ptr(-RT_EINVAL);
  370. }
  371. if (idx >= 0)
  372. {
  373. pc = &pl330->chans[idx];
  374. if (pc->enabled)
  375. {
  376. return rt_err_ptr(-RT_EBUSY);
  377. }
  378. }
  379. else
  380. {
  381. /*
  382. * Memory to Memory is often called after after DM has been initialized,
  383. * So just return unused chan
  384. */
  385. for (int i = 0; i < pl330->num_chan; ++i)
  386. {
  387. pc = &pl330->chans[i];
  388. if (!pc->enabled)
  389. {
  390. goto _found;
  391. }
  392. }
  393. return RT_NULL;
  394. }
  395. _found:
  396. pc->enabled = RT_TRUE;
  397. HWREG32(pl330->regs + PL330_REG_INTEN) |= RT_BIT(pl330_chan_id(pl330, pc));
  398. return &pc->parent;
  399. }
  400. static rt_err_t pl330_dma_release_chan(struct rt_dma_chan *chan)
  401. {
  402. struct pl330_chan *pc = rt_container_of(chan, struct pl330_chan, parent);
  403. pc->enabled = RT_FALSE;
  404. return RT_EOK;
  405. }
  406. static rt_err_t pl330_dma_start(struct rt_dma_chan *chan)
  407. {
  408. struct pl330_chan *pc = rt_container_of(chan, struct pl330_chan, parent);
  409. struct pl330 *pl330 = raw_to_pl330(chan->ctrl);
  410. while (HWREG32(pl330->regs + PL330_REG_DBGSTATUS) & PL330_DBGSTATUS_BUSY)
  411. {
  412. rt_hw_cpu_relax();
  413. }
  414. rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, pc->microcode, pc->microcode_len);
  415. HWREG32(pl330->regs + PL330_REG_DBGINST0) = ((pl330_chan_id(pl330, pc) + 1) << 8) | (PL330_CMD_DMAGO << 16);
  416. HWREG32(pl330->regs + PL330_REG_DBGINST1) = pc->microcode_dma;
  417. HWREG32(pl330->regs + PL330_REG_DBGCMD) = 0;
  418. return RT_EOK;
  419. }
  420. static rt_err_t pl330_dma_stop(struct rt_dma_chan *chan)
  421. {
  422. struct pl330_chan *pc = rt_container_of(chan, struct pl330_chan, parent);
  423. struct pl330 *pl330 = raw_to_pl330(chan->ctrl);
  424. while (HWREG32(pl330->regs + PL330_REG_DBGSTATUS) & PL330_DBGSTATUS_BUSY)
  425. {
  426. rt_hw_cpu_relax();
  427. }
  428. HWREG32(pl330->regs + PL330_REG_DBGINST0) = ((pl330_chan_id(pl330, pc) + 1) << 8) | PL330_CMD_DMAKILL;
  429. HWREG32(pl330->regs + PL330_REG_DBGINST1) = 0;
  430. HWREG32(pl330->regs + PL330_REG_DBGCMD) = 0;
  431. return RT_EOK;
  432. }
  433. static rt_err_t pl330_dma_config(struct rt_dma_chan *chan,
  434. struct rt_dma_slave_config *conf)
  435. {
  436. return RT_EOK;
  437. }
  438. static rt_err_t pl330_dma_prep_memcpy(struct rt_dma_chan *chan,
  439. rt_ubase_t dma_addr_src, rt_ubase_t dma_addr_dst, rt_size_t len)
  440. {
  441. void *mc;
  442. rt_err_t err;
  443. rt_uint32_t value;
  444. rt_size_t burst_bytes;
  445. rt_uint8_t ljmp_inner, ljmp_outer;
  446. rt_uint16_t loop, outer, rem, inner_first;
  447. struct pl330_chan *pc = rt_container_of(chan, struct pl330_chan, parent);
  448. struct pl330 *pl330 = raw_to_pl330(chan->ctrl);
  449. struct rt_dma_slave_config *conf = &chan->conf;
  450. mc = pc->microcode;
  451. if ((err = pl330_ccr_config(conf, &value)))
  452. {
  453. return err;
  454. }
  455. mc += pl330_cmd_dmamov(mc, PL330_DIR_CCR, value);
  456. mc += pl330_cmd_dmamov(mc, PL330_DIR_SAR, dma_addr_src);
  457. mc += pl330_cmd_dmamov(mc, PL330_DIR_DAR, dma_addr_dst);
  458. burst_bytes = conf->src_addr_width * conf->src_maxburst;
  459. if (!burst_bytes || !len)
  460. {
  461. return -RT_EINVAL;
  462. }
  463. if (len % burst_bytes)
  464. {
  465. LOG_E("Memcpy len(%lu) must be multiple of burst(%lu)", len, burst_bytes);
  466. return -RT_EINVAL;
  467. }
  468. /* Total iterations */
  469. loop = len / burst_bytes;
  470. if (loop == 0)
  471. {
  472. return -RT_EINVAL;
  473. }
  474. outer = loop / 256;
  475. rem = loop % 256;
  476. if (outer == 0)
  477. {
  478. outer = 1;
  479. }
  480. inner_first = (loop < 256) ? loop : 256;
  481. mc += pl330_cmd_dmalp(mc, 1, outer);
  482. ljmp_outer = mc - pc->microcode;
  483. mc += pl330_cmd_dmalp(mc, 0, inner_first);
  484. ljmp_inner = mc - pc->microcode;
  485. mc += pl330_cmd_dmald(mc, PL330_COND_ALWAYS);
  486. mc += pl330_cmd_dmast(mc, PL330_COND_ALWAYS);
  487. mc += pl330_cmd_dmalpend(mc, PL330_COND_ALWAYS, RT_FALSE, 0,
  488. mc - pc->microcode - ljmp_inner);
  489. if (rem && loop > 256)
  490. {
  491. rt_uint8_t ljmp_inner2;
  492. mc += pl330_cmd_dmalp(mc, 0, rem);
  493. ljmp_inner2 = mc - pc->microcode;
  494. mc += pl330_cmd_dmald(mc, PL330_COND_ALWAYS);
  495. mc += pl330_cmd_dmast(mc, PL330_COND_ALWAYS);
  496. mc += pl330_cmd_dmalpend(mc, PL330_COND_ALWAYS, RT_FALSE, 0,
  497. mc - pc->microcode - ljmp_inner2);
  498. }
  499. mc += pl330_cmd_dmalpend(mc, PL330_COND_ALWAYS, RT_FALSE, 1,
  500. mc - pc->microcode - ljmp_outer);
  501. mc += pl330_cmd_dmasev(mc, pl330_chan_id(pl330, pc));
  502. mc += pl330_cmd_dmaend(mc);
  503. pc->size = len;
  504. pc->microcode_len = mc - pc->microcode;
  505. return RT_EOK;
  506. }
  507. static rt_err_t pl330_dma_prep_cyclic(struct rt_dma_chan *chan,
  508. rt_ubase_t dma_buf_addr, rt_size_t buf_len, rt_size_t period_len,
  509. enum rt_dma_transfer_direction dir)
  510. {
  511. void *mc;
  512. rt_err_t err;
  513. rt_uint32_t ccr_val;
  514. rt_size_t burst_bytes;
  515. rt_uint16_t period_loop, total_periods;
  516. struct pl330_chan *pc = rt_container_of(chan, struct pl330_chan, parent);
  517. struct pl330 *pl330 = raw_to_pl330(chan->ctrl);
  518. struct rt_dma_slave_config *conf = &chan->conf;
  519. mc = pc->microcode;
  520. if ((err = pl330_ccr_config(conf, &ccr_val)))
  521. {
  522. return err;
  523. }
  524. mc += pl330_cmd_dmamov(mc, PL330_DIR_CCR, ccr_val);
  525. if (dir == RT_DMA_MEM_TO_DEV)
  526. {
  527. mc += pl330_cmd_dmamov(mc, PL330_DIR_SAR, dma_buf_addr);
  528. mc += pl330_cmd_dmamov(mc, PL330_DIR_DAR, conf->dst_addr);
  529. }
  530. else if (dir == RT_DMA_DEV_TO_MEM)
  531. {
  532. mc += pl330_cmd_dmamov(mc, PL330_DIR_SAR, conf->src_addr);
  533. mc += pl330_cmd_dmamov(mc, PL330_DIR_DAR, dma_buf_addr);
  534. }
  535. burst_bytes = conf->src_addr_width * conf->src_maxburst;
  536. if (!burst_bytes)
  537. {
  538. return -RT_EINVAL;
  539. }
  540. if (period_len % burst_bytes)
  541. {
  542. return -RT_EINVAL;
  543. }
  544. if (buf_len % period_len)
  545. {
  546. return -RT_EINVAL;
  547. }
  548. period_loop = period_len / burst_bytes;
  549. if (period_loop == 0 || period_loop > 255)
  550. {
  551. return -RT_EINVAL;
  552. }
  553. total_periods = buf_len / period_len;
  554. if (total_periods == 0)
  555. {
  556. return -RT_EINVAL;
  557. }
  558. /* Outer Loop */
  559. mc += pl330_cmd_dmalp(mc, 1 /* LC1 */, 0 /* Infinite loop */);
  560. rt_uint8_t outer_ljmp = mc - pc->microcode;
  561. /* Inner Loop */
  562. mc += pl330_cmd_dmalp(mc, 0 /* LC0 */, period_loop);
  563. rt_uint8_t inner_ljmp = mc - pc->microcode;
  564. mc += pl330_cmd_dmald(mc, PL330_COND_ALWAYS);
  565. mc += pl330_cmd_dmast(mc, PL330_COND_ALWAYS);
  566. mc += pl330_cmd_dmalpend(mc, PL330_COND_ALWAYS,
  567. RT_FALSE, 0,
  568. mc - pc->microcode - inner_ljmp);
  569. mc += pl330_cmd_dmasev(mc, pl330_chan_id(pl330, pc));
  570. /* Outer loop end */
  571. mc += pl330_cmd_dmalpend(mc, PL330_COND_ALWAYS,
  572. RT_FALSE, 1, /* LC1 */
  573. mc - pc->microcode - outer_ljmp);
  574. pc->microcode_len = mc - pc->microcode;
  575. return RT_EOK;
  576. }
  577. static rt_err_t pl330_dma_prep_single(struct rt_dma_chan *chan,
  578. rt_ubase_t dma_buf_addr, rt_size_t buf_len,
  579. enum rt_dma_transfer_direction dir)
  580. {
  581. void *mc;
  582. rt_err_t err;
  583. rt_uint16_t loop;
  584. rt_uint32_t ccr_val;
  585. rt_size_t burst_bytes;
  586. struct pl330_chan *pc = rt_container_of(chan, struct pl330_chan, parent);
  587. struct pl330 *pl330 = raw_to_pl330(chan->ctrl);
  588. struct rt_dma_slave_config *conf = &chan->conf;
  589. mc = pc->microcode;
  590. if ((err = pl330_ccr_config(conf, &ccr_val)))
  591. {
  592. return err;
  593. }
  594. mc += pl330_cmd_dmamov(mc, PL330_DIR_CCR, ccr_val);
  595. if (dir == RT_DMA_MEM_TO_DEV)
  596. {
  597. mc += pl330_cmd_dmamov(mc, PL330_DIR_SAR, dma_buf_addr);
  598. mc += pl330_cmd_dmamov(mc, PL330_DIR_DAR, conf->dst_addr);
  599. }
  600. else if (dir == RT_DMA_DEV_TO_MEM)
  601. {
  602. mc += pl330_cmd_dmamov(mc, PL330_DIR_SAR, conf->src_addr);
  603. mc += pl330_cmd_dmamov(mc, PL330_DIR_DAR, dma_buf_addr);
  604. }
  605. burst_bytes = conf->src_addr_width * conf->src_maxburst;
  606. if (!burst_bytes || !buf_len)
  607. {
  608. return -RT_EINVAL;
  609. }
  610. if (buf_len % burst_bytes)
  611. {
  612. return -RT_EINVAL;
  613. }
  614. loop = buf_len / burst_bytes;
  615. if (loop == 0 || loop > 255)
  616. {
  617. return -RT_EINVAL;
  618. }
  619. mc += pl330_cmd_dmalp(mc, 0 /* LC0 */, loop);
  620. rt_uint8_t ljmp = mc - pc->microcode;
  621. mc += pl330_cmd_dmald(mc, PL330_COND_ALWAYS);
  622. mc += pl330_cmd_dmast(mc, PL330_COND_ALWAYS);
  623. mc += pl330_cmd_dmalpend(mc,
  624. PL330_COND_ALWAYS,
  625. RT_FALSE,
  626. 0, /* LC0 */
  627. mc - pc->microcode - ljmp);
  628. mc += pl330_cmd_dmasev(mc, pl330_chan_id(pl330, pc));
  629. mc += pl330_cmd_dmaend(mc);
  630. pc->microcode_len = mc - pc->microcode;
  631. pc->size = buf_len;
  632. return RT_EOK;
  633. }
  634. static const struct rt_dma_controller_ops pl330_dma_ops =
  635. {
  636. .request_chan = pl330_dma_request_chan,
  637. .release_chan = pl330_dma_release_chan,
  638. .start = pl330_dma_start,
  639. .stop = pl330_dma_stop,
  640. .config = pl330_dma_config,
  641. .prep_memcpy = pl330_dma_prep_memcpy,
  642. .prep_cyclic = pl330_dma_prep_cyclic,
  643. .prep_single = pl330_dma_prep_single,
  644. };
  645. static void pl330_isr(int irqno, void *params)
  646. {
  647. rt_uint32_t isr, csr;
  648. struct pl330_chan *pc;
  649. struct pl330 *pl330 = params;
  650. isr = HWREG32(pl330->regs + PL330_REG_INTMIS);
  651. for (int i = 0; i < pl330->num_chan; ++i)
  652. {
  653. if (!(isr & RT_BIT(i)))
  654. {
  655. continue;
  656. }
  657. pc = &pl330->chans[i];
  658. HWREG32(pl330->regs + PL330_REG_INTCLR) = RT_BIT(i);
  659. csr = HWREG32(pl330->regs + PL330_REG_CSR(i)) & 0xf;
  660. switch (csr)
  661. {
  662. case PL330_CS_CMPLT:
  663. case PL330_CS_STOP:
  664. rt_dma_chan_done(&pc->parent, pc->size);
  665. break;
  666. case PL330_CS_FAULT:
  667. case PL330_CS_FLTCMP:
  668. LOG_E("Channel[%d] fault", i);
  669. rt_dma_chan_done(&pc->parent, 0);
  670. break;
  671. default:
  672. LOG_E("Unhandle CSR = %x", csr);
  673. break;
  674. }
  675. }
  676. }
  677. static void pl330_free(struct pl330 *pl330)
  678. {
  679. if (pl330->regs)
  680. {
  681. rt_iounmap(pl330->regs);
  682. }
  683. if (!rt_is_err_or_null(pl330->pclk))
  684. {
  685. rt_clk_disable_unprepare(pl330->pclk);
  686. rt_clk_put(pl330->pclk);
  687. }
  688. if (!rt_is_err_or_null(pl330->rstc))
  689. {
  690. rt_reset_control_assert(pl330->rstc);
  691. rt_reset_control_put(pl330->rstc);
  692. }
  693. if (!rt_is_err_or_null(pl330->rstc_ocp))
  694. {
  695. rt_reset_control_assert(pl330->rstc_ocp);
  696. rt_reset_control_put(pl330->rstc_ocp);
  697. }
  698. if (pl330->chans)
  699. {
  700. rt_free(pl330->chans);
  701. }
  702. rt_free(pl330);
  703. }
  704. static rt_err_t pl330_probe(struct rt_platform_device *pdev)
  705. {
  706. rt_err_t err;
  707. char isr_name[RT_NAME_MAX];
  708. struct rt_device *dev = &pdev->parent;
  709. struct pl330 *pl330 = rt_calloc(1, sizeof(*pl330));
  710. if (!pl330)
  711. {
  712. return -RT_ENOMEM;
  713. }
  714. pl330->regs = rt_dm_dev_iomap(dev, 0);
  715. if (!pl330->regs)
  716. {
  717. err = -RT_EIO;
  718. goto _fail;
  719. }
  720. pl330->irqs_nr = rt_dm_dev_get_irq_count(dev);
  721. if (pl330->irqs_nr < 0)
  722. {
  723. err = pl330->irqs_nr;
  724. goto _fail;
  725. }
  726. else if (pl330->irqs_nr == 0)
  727. {
  728. err = -RT_EINVAL;
  729. goto _fail;
  730. }
  731. for (int i = 0; i < pl330->irqs_nr; ++i)
  732. {
  733. int irq = rt_dm_dev_get_irq(dev, i);
  734. if (irq < 0)
  735. {
  736. err = irq;
  737. goto _fail;
  738. }
  739. pl330->irqs[i] = irq;
  740. }
  741. pl330->pclk = rt_clk_get_by_name(dev, "apb_pclk");
  742. if (rt_is_err(pl330->pclk))
  743. {
  744. err = rt_ptr_err(pl330->pclk);
  745. goto _fail;
  746. }
  747. if ((err = rt_clk_prepare_enable(pl330->pclk)))
  748. {
  749. goto _fail;
  750. }
  751. pl330->rstc = rt_reset_control_get_by_name(dev, "dma");
  752. if (rt_is_err(pl330->rstc))
  753. {
  754. err = rt_ptr_err(pl330->rstc);
  755. goto _fail;
  756. }
  757. if (pl330->rstc && (err = rt_reset_control_deassert(pl330->rstc)))
  758. {
  759. goto _fail;
  760. }
  761. pl330->rstc_ocp = rt_reset_control_get_by_name(dev, "dma-ocp");
  762. if (rt_is_err(pl330->rstc_ocp))
  763. {
  764. err = rt_ptr_err(pl330->rstc_ocp);
  765. goto _fail;
  766. }
  767. if (pl330->rstc_ocp && (err = rt_reset_control_deassert(pl330->rstc_ocp)))
  768. {
  769. goto _fail;
  770. }
  771. if (rt_dm_dev_prop_read_bool(dev, "arm,pl330-broken-no-flushp"))
  772. {
  773. pl330->quirk |= PL330_QUIRK_BROKEN_NO_FLUSHP;
  774. }
  775. if (rt_dm_dev_prop_read_bool(dev, "arm,pl330-periph-burst"))
  776. {
  777. pl330->quirk |= PL330_QUIRK_PERIPH_BURST;
  778. }
  779. pl330_read_config(pl330);
  780. pl330->chans = rt_calloc(pl330->num_chan, sizeof(pl330->chans[0]));
  781. if (!pl330->chans)
  782. {
  783. err = -RT_ENOMEM;
  784. goto _fail;
  785. }
  786. for (int i = 0; i < pl330->num_chan; ++i)
  787. {
  788. int offset = 0;
  789. struct pl330_chan *chan = &pl330->chans[i];
  790. chan->microcode_dma = (rt_ubase_t)rt_kmem_v2p(chan->microcode_raw);
  791. offset = RT_ALIGN(chan->microcode_dma, 4) - chan->microcode_dma;
  792. chan->microcode = chan->microcode_raw + offset;
  793. chan->microcode_dma += offset;
  794. }
  795. pl330->parent.dev = dev;
  796. pl330->parent.ops = &pl330_dma_ops;
  797. rt_dma_controller_add_direction(&pl330->parent, RT_DMA_MEM_TO_MEM);
  798. rt_dma_controller_add_direction(&pl330->parent, RT_DMA_MEM_TO_DEV);
  799. rt_dma_controller_add_direction(&pl330->parent, RT_DMA_DEV_TO_MEM);
  800. rt_dma_controller_set_addr_mask(&pl330->parent, RT_DMA_ADDR_MASK(32));
  801. if ((err = rt_dma_controller_register(&pl330->parent)))
  802. {
  803. goto _fail;
  804. }
  805. dev->user_data = pl330;
  806. for (int i = 0; i < pl330->irqs_nr; ++i)
  807. {
  808. rt_snprintf(isr_name, RT_NAME_MAX, "%s-%u", rt_dm_dev_get_name(dev), i);
  809. rt_hw_interrupt_install(pl330->irqs[i], pl330_isr, pl330, isr_name);
  810. rt_hw_interrupt_umask(pl330->irqs[i]);
  811. }
  812. return RT_EOK;
  813. _fail:
  814. pl330_free(pl330);
  815. return err;
  816. }
  817. static rt_err_t pl330_remove(struct rt_platform_device *pdev)
  818. {
  819. struct pl330 *pl330 = pdev->parent.user_data;
  820. for (int i = 0; i < pl330->irqs_nr; ++i)
  821. {
  822. rt_hw_interrupt_mask(pl330->irqs[i]);
  823. rt_pic_detach_irq(pl330->irqs[i], pl330);
  824. }
  825. rt_dma_controller_unregister(&pl330->parent);
  826. pl330_free(pl330);
  827. return RT_EOK;
  828. }
  829. static const struct rt_ofw_node_id pl330_ofw_ids[] =
  830. {
  831. { .compatible = "arm,pl330" },
  832. { /* sentinel */ }
  833. };
  834. static struct rt_platform_driver pl330_driver =
  835. {
  836. .name = "dma-pl330",
  837. .ids = pl330_ofw_ids,
  838. .probe = pl330_probe,
  839. .remove = pl330_remove,
  840. };
  841. static int pl330_drv_register(void)
  842. {
  843. rt_platform_driver_register(&pl330_driver);
  844. return 0;
  845. }
  846. INIT_SUBSYS_EXPORT(pl330_drv_register);