dma.c 20 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. /*
  2. * linux/arch/arm/mach-pnx4008/dma.c
  3. *
  4. * PNX4008 DMA registration and IRQ dispatching
  5. *
  6. * Author: Vitaly Wool
  7. * Copyright: MontaVista Software Inc. (c) 2005
  8. *
  9. * Based on the code from Nicolas Pitre
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. */
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/kernel.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/errno.h>
  20. #include <linux/err.h>
  21. #include <linux/dma-mapping.h>
  22. #include <linux/clk.h>
  23. #include <asm/system.h>
  24. #include <asm/irq.h>
  25. #include <asm/hardware.h>
  26. #include <asm/dma.h>
  27. #include <asm/dma-mapping.h>
  28. #include <asm/io.h>
  29. #include <asm/mach/dma.h>
  30. #include <asm/arch/clock.h>
  31. static struct dma_channel {
  32. char *name;
  33. void (*irq_handler) (int, int, void *, struct pt_regs *);
  34. void *data;
  35. struct pnx4008_dma_ll *ll;
  36. u32 ll_dma;
  37. void *target_addr;
  38. int target_id;
  39. } dma_channels[MAX_DMA_CHANNELS];
  40. static struct ll_pool {
  41. void *vaddr;
  42. void *cur;
  43. dma_addr_t dma_addr;
  44. int count;
  45. } ll_pool;
  46. static spinlock_t ll_lock = SPIN_LOCK_UNLOCKED;
  47. struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t * ll_dma)
  48. {
  49. struct pnx4008_dma_ll *ll = NULL;
  50. unsigned long flags;
  51. spin_lock_irqsave(&ll_lock, flags);
  52. if (ll_pool.count > 4) { /* can give one more */
  53. ll = *(struct pnx4008_dma_ll **) ll_pool.cur;
  54. *ll_dma = ll_pool.dma_addr + ((void *)ll - ll_pool.vaddr);
  55. *(void **)ll_pool.cur = **(void ***)ll_pool.cur;
  56. memset(ll, 0, sizeof(*ll));
  57. ll_pool.count--;
  58. }
  59. spin_unlock_irqrestore(&ll_lock, flags);
  60. return ll;
  61. }
  62. EXPORT_SYMBOL_GPL(pnx4008_alloc_ll_entry);
  63. void pnx4008_free_ll_entry(struct pnx4008_dma_ll * ll, dma_addr_t ll_dma)
  64. {
  65. unsigned long flags;
  66. if (ll) {
  67. if ((unsigned long)((long)ll - (long)ll_pool.vaddr) > 0x4000) {
  68. printk(KERN_ERR "Trying to free entry not allocated by DMA\n");
  69. BUG();
  70. }
  71. if (ll->flags & DMA_BUFFER_ALLOCATED)
  72. ll->free(ll->alloc_data);
  73. spin_lock_irqsave(&ll_lock, flags);
  74. *(long *)ll = *(long *)ll_pool.cur;
  75. *(long *)ll_pool.cur = (long)ll;
  76. ll_pool.count++;
  77. spin_unlock_irqrestore(&ll_lock, flags);
  78. }
  79. }
  80. EXPORT_SYMBOL_GPL(pnx4008_free_ll_entry);
  81. void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll * ll)
  82. {
  83. struct pnx4008_dma_ll *ptr;
  84. u32 dma;
  85. while (ll) {
  86. dma = ll->next_dma;
  87. ptr = ll->next;
  88. pnx4008_free_ll_entry(ll, ll_dma);
  89. ll_dma = dma;
  90. ll = ptr;
  91. }
  92. }
  93. EXPORT_SYMBOL_GPL(pnx4008_free_ll);
  94. static int dma_channels_requested = 0;
  95. static inline void dma_increment_usage(void)
  96. {
  97. if (!dma_channels_requested++) {
  98. struct clk *clk = clk_get(0, "dma_ck");
  99. if (!IS_ERR(clk)) {
  100. clk_set_rate(clk, 1);
  101. clk_put(clk);
  102. }
  103. pnx4008_config_dma(-1, -1, 1);
  104. }
  105. }
  106. static inline void dma_decrement_usage(void)
  107. {
  108. if (!--dma_channels_requested) {
  109. struct clk *clk = clk_get(0, "dma_ck");
  110. if (!IS_ERR(clk)) {
  111. clk_set_rate(clk, 0);
  112. clk_put(clk);
  113. }
  114. pnx4008_config_dma(-1, -1, 0);
  115. }
  116. }
  117. static spinlock_t dma_lock = SPIN_LOCK_UNLOCKED;
  118. static inline void pnx4008_dma_lock(void)
  119. {
  120. spin_lock_irq(&dma_lock);
  121. }
  122. static inline void pnx4008_dma_unlock(void)
  123. {
  124. spin_unlock_irq(&dma_lock);
  125. }
  126. #define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
  127. int pnx4008_request_channel(char *name, int ch,
  128. void (*irq_handler) (int, int, void *,
  129. struct pt_regs *), void *data)
  130. {
  131. int i, found = 0;
  132. /* basic sanity checks */
  133. if (!name || (ch != -1 && !VALID_CHANNEL(ch)))
  134. return -EINVAL;
  135. pnx4008_dma_lock();
  136. /* try grabbing a DMA channel with the requested priority */
  137. for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
  138. if (!dma_channels[i].name && (ch == -1 || ch == i)) {
  139. found = 1;
  140. break;
  141. }
  142. }
  143. if (found) {
  144. dma_increment_usage();
  145. dma_channels[i].name = name;
  146. dma_channels[i].irq_handler = irq_handler;
  147. dma_channels[i].data = data;
  148. dma_channels[i].ll = NULL;
  149. dma_channels[i].ll_dma = 0;
  150. } else {
  151. printk(KERN_WARNING "No more available DMA channels for %s\n",
  152. name);
  153. i = -ENODEV;
  154. }
  155. pnx4008_dma_unlock();
  156. return i;
  157. }
  158. EXPORT_SYMBOL_GPL(pnx4008_request_channel);
  159. void pnx4008_free_channel(int ch)
  160. {
  161. if (!dma_channels[ch].name) {
  162. printk(KERN_CRIT
  163. "%s: trying to free channel %d which is already freed\n",
  164. __FUNCTION__, ch);
  165. return;
  166. }
  167. pnx4008_dma_lock();
  168. pnx4008_free_ll(dma_channels[ch].ll_dma, dma_channels[ch].ll);
  169. dma_channels[ch].ll = NULL;
  170. dma_decrement_usage();
  171. dma_channels[ch].name = NULL;
  172. pnx4008_dma_unlock();
  173. }
  174. EXPORT_SYMBOL_GPL(pnx4008_free_channel);
  175. int pnx4008_config_dma(int ahb_m1_be, int ahb_m2_be, int enable)
  176. {
  177. unsigned long dma_cfg = __raw_readl(DMAC_CONFIG);
  178. switch (ahb_m1_be) {
  179. case 0:
  180. dma_cfg &= ~(1 << 1);
  181. break;
  182. case 1:
  183. dma_cfg |= (1 << 1);
  184. break;
  185. default:
  186. break;
  187. }
  188. switch (ahb_m2_be) {
  189. case 0:
  190. dma_cfg &= ~(1 << 2);
  191. break;
  192. case 1:
  193. dma_cfg |= (1 << 2);
  194. break;
  195. default:
  196. break;
  197. }
  198. switch (enable) {
  199. case 0:
  200. dma_cfg &= ~(1 << 0);
  201. break;
  202. case 1:
  203. dma_cfg |= (1 << 0);
  204. break;
  205. default:
  206. break;
  207. }
  208. pnx4008_dma_lock();
  209. __raw_writel(dma_cfg, DMAC_CONFIG);
  210. pnx4008_dma_unlock();
  211. return 0;
  212. }
  213. EXPORT_SYMBOL_GPL(pnx4008_config_dma);
  214. int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl * ch_ctrl,
  215. unsigned long *ctrl)
  216. {
  217. int i = 0, dbsize, sbsize, err = 0;
  218. if (!ctrl || !ch_ctrl) {
  219. err = -EINVAL;
  220. goto out;
  221. }
  222. *ctrl = 0;
  223. switch (ch_ctrl->tc_mask) {
  224. case 0:
  225. break;
  226. case 1:
  227. *ctrl |= (1 << 31);
  228. break;
  229. default:
  230. err = -EINVAL;
  231. goto out;
  232. }
  233. switch (ch_ctrl->cacheable) {
  234. case 0:
  235. break;
  236. case 1:
  237. *ctrl |= (1 << 30);
  238. break;
  239. default:
  240. err = -EINVAL;
  241. goto out;
  242. }
  243. switch (ch_ctrl->bufferable) {
  244. case 0:
  245. break;
  246. case 1:
  247. *ctrl |= (1 << 29);
  248. break;
  249. default:
  250. err = -EINVAL;
  251. goto out;
  252. }
  253. switch (ch_ctrl->priv_mode) {
  254. case 0:
  255. break;
  256. case 1:
  257. *ctrl |= (1 << 28);
  258. break;
  259. default:
  260. err = -EINVAL;
  261. goto out;
  262. }
  263. switch (ch_ctrl->di) {
  264. case 0:
  265. break;
  266. case 1:
  267. *ctrl |= (1 << 27);
  268. break;
  269. default:
  270. err = -EINVAL;
  271. goto out;
  272. }
  273. switch (ch_ctrl->si) {
  274. case 0:
  275. break;
  276. case 1:
  277. *ctrl |= (1 << 26);
  278. break;
  279. default:
  280. err = -EINVAL;
  281. goto out;
  282. }
  283. switch (ch_ctrl->dest_ahb1) {
  284. case 0:
  285. break;
  286. case 1:
  287. *ctrl |= (1 << 25);
  288. break;
  289. default:
  290. err = -EINVAL;
  291. goto out;
  292. }
  293. switch (ch_ctrl->src_ahb1) {
  294. case 0:
  295. break;
  296. case 1:
  297. *ctrl |= (1 << 24);
  298. break;
  299. default:
  300. err = -EINVAL;
  301. goto out;
  302. }
  303. switch (ch_ctrl->dwidth) {
  304. case WIDTH_BYTE:
  305. *ctrl &= ~(7 << 21);
  306. break;
  307. case WIDTH_HWORD:
  308. *ctrl &= ~(7 << 21);
  309. *ctrl |= (1 << 21);
  310. break;
  311. case WIDTH_WORD:
  312. *ctrl &= ~(7 << 21);
  313. *ctrl |= (2 << 21);
  314. break;
  315. default:
  316. err = -EINVAL;
  317. goto out;
  318. }
  319. switch (ch_ctrl->swidth) {
  320. case WIDTH_BYTE:
  321. *ctrl &= ~(7 << 18);
  322. break;
  323. case WIDTH_HWORD:
  324. *ctrl &= ~(7 << 18);
  325. *ctrl |= (1 << 18);
  326. break;
  327. case WIDTH_WORD:
  328. *ctrl &= ~(7 << 18);
  329. *ctrl |= (2 << 18);
  330. break;
  331. default:
  332. err = -EINVAL;
  333. goto out;
  334. }
  335. dbsize = ch_ctrl->dbsize;
  336. while (!(dbsize & 1)) {
  337. i++;
  338. dbsize >>= 1;
  339. }
  340. if (ch_ctrl->dbsize != 1 || i > 8 || i == 1) {
  341. err = -EINVAL;
  342. goto out;
  343. } else if (i > 1)
  344. i--;
  345. *ctrl &= ~(7 << 15);
  346. *ctrl |= (i << 15);
  347. sbsize = ch_ctrl->sbsize;
  348. while (!(sbsize & 1)) {
  349. i++;
  350. sbsize >>= 1;
  351. }
  352. if (ch_ctrl->sbsize != 1 || i > 8 || i == 1) {
  353. err = -EINVAL;
  354. goto out;
  355. } else if (i > 1)
  356. i--;
  357. *ctrl &= ~(7 << 12);
  358. *ctrl |= (i << 12);
  359. if (ch_ctrl->tr_size > 0x7ff) {
  360. err = -E2BIG;
  361. goto out;
  362. }
  363. *ctrl &= ~0x7ff;
  364. *ctrl |= ch_ctrl->tr_size & 0x7ff;
  365. out:
  366. return err;
  367. }
  368. EXPORT_SYMBOL_GPL(pnx4008_dma_pack_control);
  369. int pnx4008_dma_parse_control(unsigned long ctrl,
  370. struct pnx4008_dma_ch_ctrl * ch_ctrl)
  371. {
  372. int err = 0;
  373. if (!ch_ctrl) {
  374. err = -EINVAL;
  375. goto out;
  376. }
  377. ch_ctrl->tr_size = ctrl & 0x7ff;
  378. ctrl >>= 12;
  379. ch_ctrl->sbsize = 1 << (ctrl & 7);
  380. if (ch_ctrl->sbsize > 1)
  381. ch_ctrl->sbsize <<= 1;
  382. ctrl >>= 3;
  383. ch_ctrl->dbsize = 1 << (ctrl & 7);
  384. if (ch_ctrl->dbsize > 1)
  385. ch_ctrl->dbsize <<= 1;
  386. ctrl >>= 3;
  387. switch (ctrl & 7) {
  388. case 0:
  389. ch_ctrl->swidth = WIDTH_BYTE;
  390. break;
  391. case 1:
  392. ch_ctrl->swidth = WIDTH_HWORD;
  393. break;
  394. case 2:
  395. ch_ctrl->swidth = WIDTH_WORD;
  396. break;
  397. default:
  398. err = -EINVAL;
  399. goto out;
  400. }
  401. ctrl >>= 3;
  402. switch (ctrl & 7) {
  403. case 0:
  404. ch_ctrl->dwidth = WIDTH_BYTE;
  405. break;
  406. case 1:
  407. ch_ctrl->dwidth = WIDTH_HWORD;
  408. break;
  409. case 2:
  410. ch_ctrl->dwidth = WIDTH_WORD;
  411. break;
  412. default:
  413. err = -EINVAL;
  414. goto out;
  415. }
  416. ctrl >>= 3;
  417. ch_ctrl->src_ahb1 = ctrl & 1;
  418. ctrl >>= 1;
  419. ch_ctrl->dest_ahb1 = ctrl & 1;
  420. ctrl >>= 1;
  421. ch_ctrl->si = ctrl & 1;
  422. ctrl >>= 1;
  423. ch_ctrl->di = ctrl & 1;
  424. ctrl >>= 1;
  425. ch_ctrl->priv_mode = ctrl & 1;
  426. ctrl >>= 1;
  427. ch_ctrl->bufferable = ctrl & 1;
  428. ctrl >>= 1;
  429. ch_ctrl->cacheable = ctrl & 1;
  430. ctrl >>= 1;
  431. ch_ctrl->tc_mask = ctrl & 1;
  432. out:
  433. return err;
  434. }
  435. EXPORT_SYMBOL_GPL(pnx4008_dma_parse_control);
  436. int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config * ch_cfg,
  437. unsigned long *cfg)
  438. {
  439. int err = 0;
  440. if (!cfg || !ch_cfg) {
  441. err = -EINVAL;
  442. goto out;
  443. }
  444. *cfg = 0;
  445. switch (ch_cfg->halt) {
  446. case 0:
  447. break;
  448. case 1:
  449. *cfg |= (1 << 18);
  450. break;
  451. default:
  452. err = -EINVAL;
  453. goto out;
  454. }
  455. switch (ch_cfg->active) {
  456. case 0:
  457. break;
  458. case 1:
  459. *cfg |= (1 << 17);
  460. break;
  461. default:
  462. err = -EINVAL;
  463. goto out;
  464. }
  465. switch (ch_cfg->lock) {
  466. case 0:
  467. break;
  468. case 1:
  469. *cfg |= (1 << 16);
  470. break;
  471. default:
  472. err = -EINVAL;
  473. goto out;
  474. }
  475. switch (ch_cfg->itc) {
  476. case 0:
  477. break;
  478. case 1:
  479. *cfg |= (1 << 15);
  480. break;
  481. default:
  482. err = -EINVAL;
  483. goto out;
  484. }
  485. switch (ch_cfg->ie) {
  486. case 0:
  487. break;
  488. case 1:
  489. *cfg |= (1 << 14);
  490. break;
  491. default:
  492. err = -EINVAL;
  493. goto out;
  494. }
  495. switch (ch_cfg->flow_cntrl) {
  496. case FC_MEM2MEM_DMA:
  497. *cfg &= ~(7 << 11);
  498. break;
  499. case FC_MEM2PER_DMA:
  500. *cfg &= ~(7 << 11);
  501. *cfg |= (1 << 11);
  502. break;
  503. case FC_PER2MEM_DMA:
  504. *cfg &= ~(7 << 11);
  505. *cfg |= (2 << 11);
  506. break;
  507. case FC_PER2PER_DMA:
  508. *cfg &= ~(7 << 11);
  509. *cfg |= (3 << 11);
  510. break;
  511. case FC_PER2PER_DPER:
  512. *cfg &= ~(7 << 11);
  513. *cfg |= (4 << 11);
  514. break;
  515. case FC_MEM2PER_PER:
  516. *cfg &= ~(7 << 11);
  517. *cfg |= (5 << 11);
  518. break;
  519. case FC_PER2MEM_PER:
  520. *cfg &= ~(7 << 11);
  521. *cfg |= (6 << 11);
  522. break;
  523. case FC_PER2PER_SPER:
  524. *cfg |= (7 << 11);
  525. break;
  526. default:
  527. err = -EINVAL;
  528. goto out;
  529. }
  530. *cfg &= ~(0x1f << 6);
  531. *cfg |= ((ch_cfg->dest_per & 0x1f) << 6);
  532. *cfg &= ~(0x1f << 1);
  533. *cfg |= ((ch_cfg->src_per & 0x1f) << 1);
  534. out:
  535. return err;
  536. }
  537. EXPORT_SYMBOL_GPL(pnx4008_dma_pack_config);
  538. int pnx4008_dma_parse_config(unsigned long cfg,
  539. struct pnx4008_dma_ch_config * ch_cfg)
  540. {
  541. int err = 0;
  542. if (!ch_cfg) {
  543. err = -EINVAL;
  544. goto out;
  545. }
  546. cfg >>= 1;
  547. ch_cfg->src_per = cfg & 0x1f;
  548. cfg >>= 5;
  549. ch_cfg->dest_per = cfg & 0x1f;
  550. cfg >>= 5;
  551. switch (cfg & 7) {
  552. case 0:
  553. ch_cfg->flow_cntrl = FC_MEM2MEM_DMA;
  554. break;
  555. case 1:
  556. ch_cfg->flow_cntrl = FC_MEM2PER_DMA;
  557. break;
  558. case 2:
  559. ch_cfg->flow_cntrl = FC_PER2MEM_DMA;
  560. break;
  561. case 3:
  562. ch_cfg->flow_cntrl = FC_PER2PER_DMA;
  563. break;
  564. case 4:
  565. ch_cfg->flow_cntrl = FC_PER2PER_DPER;
  566. break;
  567. case 5:
  568. ch_cfg->flow_cntrl = FC_MEM2PER_PER;
  569. break;
  570. case 6:
  571. ch_cfg->flow_cntrl = FC_PER2MEM_PER;
  572. break;
  573. case 7:
  574. ch_cfg->flow_cntrl = FC_PER2PER_SPER;
  575. }
  576. cfg >>= 3;
  577. ch_cfg->ie = cfg & 1;
  578. cfg >>= 1;
  579. ch_cfg->itc = cfg & 1;
  580. cfg >>= 1;
  581. ch_cfg->lock = cfg & 1;
  582. cfg >>= 1;
  583. ch_cfg->active = cfg & 1;
  584. cfg >>= 1;
  585. ch_cfg->halt = cfg & 1;
  586. out:
  587. return err;
  588. }
  589. EXPORT_SYMBOL_GPL(pnx4008_dma_parse_config);
  590. void pnx4008_dma_split_head_entry(struct pnx4008_dma_config * config,
  591. struct pnx4008_dma_ch_ctrl * ctrl)
  592. {
  593. int new_len = ctrl->tr_size, num_entries = 0;
  594. int old_len = new_len;
  595. int src_width, dest_width, count = 1;
  596. switch (ctrl->swidth) {
  597. case WIDTH_BYTE:
  598. src_width = 1;
  599. break;
  600. case WIDTH_HWORD:
  601. src_width = 2;
  602. break;
  603. case WIDTH_WORD:
  604. src_width = 4;
  605. break;
  606. default:
  607. return;
  608. }
  609. switch (ctrl->dwidth) {
  610. case WIDTH_BYTE:
  611. dest_width = 1;
  612. break;
  613. case WIDTH_HWORD:
  614. dest_width = 2;
  615. break;
  616. case WIDTH_WORD:
  617. dest_width = 4;
  618. break;
  619. default:
  620. return;
  621. }
  622. while (new_len > 0x7FF) {
  623. num_entries++;
  624. new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
  625. }
  626. if (num_entries != 0) {
  627. struct pnx4008_dma_ll *ll = NULL;
  628. config->ch_ctrl &= ~0x7ff;
  629. config->ch_ctrl |= new_len;
  630. if (!config->is_ll) {
  631. config->is_ll = 1;
  632. while (num_entries) {
  633. if (!ll) {
  634. config->ll =
  635. pnx4008_alloc_ll_entry(&config->
  636. ll_dma);
  637. ll = config->ll;
  638. } else {
  639. ll->next =
  640. pnx4008_alloc_ll_entry(&ll->
  641. next_dma);
  642. ll = ll->next;
  643. }
  644. if (ctrl->si)
  645. ll->src_addr =
  646. config->src_addr +
  647. src_width * new_len * count;
  648. else
  649. ll->src_addr = config->src_addr;
  650. if (ctrl->di)
  651. ll->dest_addr =
  652. config->dest_addr +
  653. dest_width * new_len * count;
  654. else
  655. ll->dest_addr = config->dest_addr;
  656. ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
  657. ll->next_dma = 0;
  658. ll->next = NULL;
  659. num_entries--;
  660. count++;
  661. }
  662. } else {
  663. struct pnx4008_dma_ll *ll_old = config->ll;
  664. unsigned long ll_dma_old = config->ll_dma;
  665. while (num_entries) {
  666. if (!ll) {
  667. config->ll =
  668. pnx4008_alloc_ll_entry(&config->
  669. ll_dma);
  670. ll = config->ll;
  671. } else {
  672. ll->next =
  673. pnx4008_alloc_ll_entry(&ll->
  674. next_dma);
  675. ll = ll->next;
  676. }
  677. if (ctrl->si)
  678. ll->src_addr =
  679. config->src_addr +
  680. src_width * new_len * count;
  681. else
  682. ll->src_addr = config->src_addr;
  683. if (ctrl->di)
  684. ll->dest_addr =
  685. config->dest_addr +
  686. dest_width * new_len * count;
  687. else
  688. ll->dest_addr = config->dest_addr;
  689. ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
  690. ll->next_dma = 0;
  691. ll->next = NULL;
  692. num_entries--;
  693. count++;
  694. }
  695. ll->next_dma = ll_dma_old;
  696. ll->next = ll_old;
  697. }
  698. /* adjust last length/tc */
  699. ll->ch_ctrl = config->ch_ctrl & (~0x7ff);
  700. ll->ch_ctrl |= old_len - new_len * (count - 1);
  701. config->ch_ctrl &= 0x7fffffff;
  702. }
  703. }
  704. EXPORT_SYMBOL_GPL(pnx4008_dma_split_head_entry);
  705. void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll * cur_ll,
  706. struct pnx4008_dma_ch_ctrl * ctrl)
  707. {
  708. int new_len = ctrl->tr_size, num_entries = 0;
  709. int old_len = new_len;
  710. int src_width, dest_width, count = 1;
  711. switch (ctrl->swidth) {
  712. case WIDTH_BYTE:
  713. src_width = 1;
  714. break;
  715. case WIDTH_HWORD:
  716. src_width = 2;
  717. break;
  718. case WIDTH_WORD:
  719. src_width = 4;
  720. break;
  721. default:
  722. return;
  723. }
  724. switch (ctrl->dwidth) {
  725. case WIDTH_BYTE:
  726. dest_width = 1;
  727. break;
  728. case WIDTH_HWORD:
  729. dest_width = 2;
  730. break;
  731. case WIDTH_WORD:
  732. dest_width = 4;
  733. break;
  734. default:
  735. return;
  736. }
  737. while (new_len > 0x7FF) {
  738. num_entries++;
  739. new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
  740. }
  741. if (num_entries != 0) {
  742. struct pnx4008_dma_ll *ll = NULL;
  743. cur_ll->ch_ctrl &= ~0x7ff;
  744. cur_ll->ch_ctrl |= new_len;
  745. if (!cur_ll->next) {
  746. while (num_entries) {
  747. if (!ll) {
  748. cur_ll->next =
  749. pnx4008_alloc_ll_entry(&cur_ll->
  750. next_dma);
  751. ll = cur_ll->next;
  752. } else {
  753. ll->next =
  754. pnx4008_alloc_ll_entry(&ll->
  755. next_dma);
  756. ll = ll->next;
  757. }
  758. if (ctrl->si)
  759. ll->src_addr =
  760. cur_ll->src_addr +
  761. src_width * new_len * count;
  762. else
  763. ll->src_addr = cur_ll->src_addr;
  764. if (ctrl->di)
  765. ll->dest_addr =
  766. cur_ll->dest_addr +
  767. dest_width * new_len * count;
  768. else
  769. ll->dest_addr = cur_ll->dest_addr;
  770. ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
  771. ll->next_dma = 0;
  772. ll->next = NULL;
  773. num_entries--;
  774. count++;
  775. }
  776. } else {
  777. struct pnx4008_dma_ll *ll_old = cur_ll->next;
  778. unsigned long ll_dma_old = cur_ll->next_dma;
  779. while (num_entries) {
  780. if (!ll) {
  781. cur_ll->next =
  782. pnx4008_alloc_ll_entry(&cur_ll->
  783. next_dma);
  784. ll = cur_ll->next;
  785. } else {
  786. ll->next =
  787. pnx4008_alloc_ll_entry(&ll->
  788. next_dma);
  789. ll = ll->next;
  790. }
  791. if (ctrl->si)
  792. ll->src_addr =
  793. cur_ll->src_addr +
  794. src_width * new_len * count;
  795. else
  796. ll->src_addr = cur_ll->src_addr;
  797. if (ctrl->di)
  798. ll->dest_addr =
  799. cur_ll->dest_addr +
  800. dest_width * new_len * count;
  801. else
  802. ll->dest_addr = cur_ll->dest_addr;
  803. ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
  804. ll->next_dma = 0;
  805. ll->next = NULL;
  806. num_entries--;
  807. count++;
  808. }
  809. ll->next_dma = ll_dma_old;
  810. ll->next = ll_old;
  811. }
  812. /* adjust last length/tc */
  813. ll->ch_ctrl = cur_ll->ch_ctrl & (~0x7ff);
  814. ll->ch_ctrl |= old_len - new_len * (count - 1);
  815. cur_ll->ch_ctrl &= 0x7fffffff;
  816. }
  817. }
  818. EXPORT_SYMBOL_GPL(pnx4008_dma_split_ll_entry);
  819. int pnx4008_config_channel(int ch, struct pnx4008_dma_config * config)
  820. {
  821. if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
  822. return -EINVAL;
  823. pnx4008_dma_lock();
  824. __raw_writel(config->src_addr, DMAC_Cx_SRC_ADDR(ch));
  825. __raw_writel(config->dest_addr, DMAC_Cx_DEST_ADDR(ch));
  826. if (config->is_ll)
  827. __raw_writel(config->ll_dma, DMAC_Cx_LLI(ch));
  828. else
  829. __raw_writel(0, DMAC_Cx_LLI(ch));
  830. __raw_writel(config->ch_ctrl, DMAC_Cx_CONTROL(ch));
  831. __raw_writel(config->ch_cfg, DMAC_Cx_CONFIG(ch));
  832. pnx4008_dma_unlock();
  833. return 0;
  834. }
  835. EXPORT_SYMBOL_GPL(pnx4008_config_channel);
  836. int pnx4008_channel_get_config(int ch, struct pnx4008_dma_config * config)
  837. {
  838. if (!VALID_CHANNEL(ch) || !dma_channels[ch].name || !config)
  839. return -EINVAL;
  840. pnx4008_dma_lock();
  841. config->ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
  842. config->ch_ctrl = __raw_readl(DMAC_Cx_CONTROL(ch));
  843. config->ll_dma = __raw_readl(DMAC_Cx_LLI(ch));
  844. config->is_ll = config->ll_dma ? 1 : 0;
  845. config->src_addr = __raw_readl(DMAC_Cx_SRC_ADDR(ch));
  846. config->dest_addr = __raw_readl(DMAC_Cx_DEST_ADDR(ch));
  847. pnx4008_dma_unlock();
  848. return 0;
  849. }
  850. EXPORT_SYMBOL_GPL(pnx4008_channel_get_config);
  851. int pnx4008_dma_ch_enable(int ch)
  852. {
  853. unsigned long ch_cfg;
  854. if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
  855. return -EINVAL;
  856. pnx4008_dma_lock();
  857. ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
  858. ch_cfg |= 1;
  859. __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
  860. pnx4008_dma_unlock();
  861. return 0;
  862. }
  863. EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enable);
  864. int pnx4008_dma_ch_disable(int ch)
  865. {
  866. unsigned long ch_cfg;
  867. if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
  868. return -EINVAL;
  869. pnx4008_dma_lock();
  870. ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
  871. ch_cfg &= ~1;
  872. __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
  873. pnx4008_dma_unlock();
  874. return 0;
  875. }
  876. EXPORT_SYMBOL_GPL(pnx4008_dma_ch_disable);
  877. int pnx4008_dma_ch_enabled(int ch)
  878. {
  879. unsigned long ch_cfg;
  880. if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
  881. return -EINVAL;
  882. pnx4008_dma_lock();
  883. ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
  884. pnx4008_dma_unlock();
  885. return ch_cfg & 1;
  886. }
  887. EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
  888. static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
  889. {
  890. int i;
  891. unsigned long dint = __raw_readl(DMAC_INT_STAT);
  892. unsigned long tcint = __raw_readl(DMAC_INT_TC_STAT);
  893. unsigned long eint = __raw_readl(DMAC_INT_ERR_STAT);
  894. unsigned long i_bit;
  895. for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
  896. i_bit = 1 << i;
  897. if (dint & i_bit) {
  898. struct dma_channel *channel = &dma_channels[i];
  899. if (channel->name && channel->irq_handler) {
  900. int cause = 0;
  901. if (eint & i_bit)
  902. cause |= DMA_ERR_INT;
  903. if (tcint & i_bit)
  904. cause |= DMA_TC_INT;
  905. channel->irq_handler(i, cause, channel->data,
  906. regs);
  907. } else {
  908. /*
  909. * IRQ for an unregistered DMA channel
  910. */
  911. printk(KERN_WARNING
  912. "spurious IRQ for DMA channel %d\n", i);
  913. }
  914. if (tcint & i_bit)
  915. __raw_writel(i_bit, DMAC_INT_TC_CLEAR);
  916. if (eint & i_bit)
  917. __raw_writel(i_bit, DMAC_INT_ERR_CLEAR);
  918. }
  919. }
  920. return IRQ_HANDLED;
  921. }
  922. static int __init pnx4008_dma_init(void)
  923. {
  924. int ret, i;
  925. ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
  926. if (ret) {
  927. printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n");
  928. goto out;
  929. }
  930. ll_pool.count = 0x4000 / sizeof(struct pnx4008_dma_ll);
  931. ll_pool.cur = ll_pool.vaddr =
  932. dma_alloc_coherent(NULL, ll_pool.count * sizeof(struct pnx4008_dma_ll),
  933. &ll_pool.dma_addr, GFP_KERNEL);
  934. if (!ll_pool.vaddr) {
  935. ret = -ENOMEM;
  936. free_irq(DMA_INT, NULL);
  937. goto out;
  938. }
  939. for (i = 0; i < ll_pool.count - 1; i++) {
  940. void **addr = ll_pool.vaddr + i * sizeof(struct pnx4008_dma_ll);
  941. *addr = (void *)addr + sizeof(struct pnx4008_dma_ll);
  942. }
  943. *(long *)(ll_pool.vaddr +
  944. (ll_pool.count - 1) * sizeof(struct pnx4008_dma_ll)) =
  945. (long)ll_pool.vaddr;
  946. __raw_writel(1, DMAC_CONFIG);
  947. out:
  948. return ret;
  949. }
  950. arch_initcall(pnx4008_dma_init);