Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[wrt350n-kernel.git] / arch / arm / mach-pnx4008 / dma.c
blob8093094c69132dfb6475a457c0e057ebe02be3de
1 /*
2 * linux/arch/arm/mach-pnx4008/dma.c
4 * PNX4008 DMA registration and IRQ dispatching
6 * Author: Vitaly Wool
7 * Copyright: MontaVista Software Inc. (c) 2005
9 * Based on the code from Nicolas Pitre
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.
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/interrupt.h>
20 #include <linux/errno.h>
21 #include <linux/err.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/clk.h>
25 #include <asm/system.h>
26 #include <asm/hardware.h>
27 #include <asm/dma.h>
28 #include <asm/dma-mapping.h>
29 #include <asm/io.h>
30 #include <asm/mach/dma.h>
31 #include <asm/arch/clock.h>
33 static struct dma_channel {
34 char *name;
35 void (*irq_handler) (int, int, void *);
36 void *data;
37 struct pnx4008_dma_ll *ll;
38 u32 ll_dma;
39 void *target_addr;
40 int target_id;
41 } dma_channels[MAX_DMA_CHANNELS];
43 static struct ll_pool {
44 void *vaddr;
45 void *cur;
46 dma_addr_t dma_addr;
47 int count;
48 } ll_pool;
50 static DEFINE_SPINLOCK(ll_lock);
52 struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t * ll_dma)
54 struct pnx4008_dma_ll *ll = NULL;
55 unsigned long flags;
57 spin_lock_irqsave(&ll_lock, flags);
58 if (ll_pool.count > 4) { /* can give one more */
59 ll = *(struct pnx4008_dma_ll **) ll_pool.cur;
60 *ll_dma = ll_pool.dma_addr + ((void *)ll - ll_pool.vaddr);
61 *(void **)ll_pool.cur = **(void ***)ll_pool.cur;
62 memset(ll, 0, sizeof(*ll));
63 ll_pool.count--;
65 spin_unlock_irqrestore(&ll_lock, flags);
67 return ll;
70 EXPORT_SYMBOL_GPL(pnx4008_alloc_ll_entry);
72 void pnx4008_free_ll_entry(struct pnx4008_dma_ll * ll, dma_addr_t ll_dma)
74 unsigned long flags;
76 if (ll) {
77 if ((unsigned long)((long)ll - (long)ll_pool.vaddr) > 0x4000) {
78 printk(KERN_ERR "Trying to free entry not allocated by DMA\n");
79 BUG();
82 if (ll->flags & DMA_BUFFER_ALLOCATED)
83 ll->free(ll->alloc_data);
85 spin_lock_irqsave(&ll_lock, flags);
86 *(long *)ll = *(long *)ll_pool.cur;
87 *(long *)ll_pool.cur = (long)ll;
88 ll_pool.count++;
89 spin_unlock_irqrestore(&ll_lock, flags);
93 EXPORT_SYMBOL_GPL(pnx4008_free_ll_entry);
95 void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll * ll)
97 struct pnx4008_dma_ll *ptr;
98 u32 dma;
100 while (ll) {
101 dma = ll->next_dma;
102 ptr = ll->next;
103 pnx4008_free_ll_entry(ll, ll_dma);
105 ll_dma = dma;
106 ll = ptr;
110 EXPORT_SYMBOL_GPL(pnx4008_free_ll);
112 static int dma_channels_requested = 0;
114 static inline void dma_increment_usage(void)
116 if (!dma_channels_requested++) {
117 struct clk *clk = clk_get(0, "dma_ck");
118 if (!IS_ERR(clk)) {
119 clk_set_rate(clk, 1);
120 clk_put(clk);
122 pnx4008_config_dma(-1, -1, 1);
125 static inline void dma_decrement_usage(void)
127 if (!--dma_channels_requested) {
128 struct clk *clk = clk_get(0, "dma_ck");
129 if (!IS_ERR(clk)) {
130 clk_set_rate(clk, 0);
131 clk_put(clk);
133 pnx4008_config_dma(-1, -1, 0);
138 static DEFINE_SPINLOCK(dma_lock);
140 static inline void pnx4008_dma_lock(void)
142 spin_lock_irq(&dma_lock);
145 static inline void pnx4008_dma_unlock(void)
147 spin_unlock_irq(&dma_lock);
150 #define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
152 int pnx4008_request_channel(char *name, int ch,
153 void (*irq_handler) (int, int, void *), void *data)
155 int i, found = 0;
157 /* basic sanity checks */
158 if (!name || (ch != -1 && !VALID_CHANNEL(ch)))
159 return -EINVAL;
161 pnx4008_dma_lock();
163 /* try grabbing a DMA channel with the requested priority */
164 for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
165 if (!dma_channels[i].name && (ch == -1 || ch == i)) {
166 found = 1;
167 break;
171 if (found) {
172 dma_increment_usage();
173 dma_channels[i].name = name;
174 dma_channels[i].irq_handler = irq_handler;
175 dma_channels[i].data = data;
176 dma_channels[i].ll = NULL;
177 dma_channels[i].ll_dma = 0;
178 } else {
179 printk(KERN_WARNING "No more available DMA channels for %s\n",
180 name);
181 i = -ENODEV;
184 pnx4008_dma_unlock();
185 return i;
188 EXPORT_SYMBOL_GPL(pnx4008_request_channel);
190 void pnx4008_free_channel(int ch)
192 if (!dma_channels[ch].name) {
193 printk(KERN_CRIT
194 "%s: trying to free channel %d which is already freed\n",
195 <<<<<<< HEAD:arch/arm/mach-pnx4008/dma.c
196 __FUNCTION__, ch);
197 =======
198 __func__, ch);
199 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:arch/arm/mach-pnx4008/dma.c
200 return;
203 pnx4008_dma_lock();
204 pnx4008_free_ll(dma_channels[ch].ll_dma, dma_channels[ch].ll);
205 dma_channels[ch].ll = NULL;
206 dma_decrement_usage();
208 dma_channels[ch].name = NULL;
209 pnx4008_dma_unlock();
212 EXPORT_SYMBOL_GPL(pnx4008_free_channel);
214 int pnx4008_config_dma(int ahb_m1_be, int ahb_m2_be, int enable)
216 unsigned long dma_cfg = __raw_readl(DMAC_CONFIG);
218 switch (ahb_m1_be) {
219 case 0:
220 dma_cfg &= ~(1 << 1);
221 break;
222 case 1:
223 dma_cfg |= (1 << 1);
224 break;
225 default:
226 break;
229 switch (ahb_m2_be) {
230 case 0:
231 dma_cfg &= ~(1 << 2);
232 break;
233 case 1:
234 dma_cfg |= (1 << 2);
235 break;
236 default:
237 break;
240 switch (enable) {
241 case 0:
242 dma_cfg &= ~(1 << 0);
243 break;
244 case 1:
245 dma_cfg |= (1 << 0);
246 break;
247 default:
248 break;
251 pnx4008_dma_lock();
252 __raw_writel(dma_cfg, DMAC_CONFIG);
253 pnx4008_dma_unlock();
255 return 0;
258 EXPORT_SYMBOL_GPL(pnx4008_config_dma);
260 int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl * ch_ctrl,
261 unsigned long *ctrl)
263 int i = 0, dbsize, sbsize, err = 0;
265 if (!ctrl || !ch_ctrl) {
266 err = -EINVAL;
267 goto out;
270 *ctrl = 0;
272 switch (ch_ctrl->tc_mask) {
273 case 0:
274 break;
275 case 1:
276 *ctrl |= (1 << 31);
277 break;
279 default:
280 err = -EINVAL;
281 goto out;
284 switch (ch_ctrl->cacheable) {
285 case 0:
286 break;
287 case 1:
288 *ctrl |= (1 << 30);
289 break;
291 default:
292 err = -EINVAL;
293 goto out;
295 switch (ch_ctrl->bufferable) {
296 case 0:
297 break;
298 case 1:
299 *ctrl |= (1 << 29);
300 break;
302 default:
303 err = -EINVAL;
304 goto out;
306 switch (ch_ctrl->priv_mode) {
307 case 0:
308 break;
309 case 1:
310 *ctrl |= (1 << 28);
311 break;
313 default:
314 err = -EINVAL;
315 goto out;
317 switch (ch_ctrl->di) {
318 case 0:
319 break;
320 case 1:
321 *ctrl |= (1 << 27);
322 break;
324 default:
325 err = -EINVAL;
326 goto out;
328 switch (ch_ctrl->si) {
329 case 0:
330 break;
331 case 1:
332 *ctrl |= (1 << 26);
333 break;
335 default:
336 err = -EINVAL;
337 goto out;
339 switch (ch_ctrl->dest_ahb1) {
340 case 0:
341 break;
342 case 1:
343 *ctrl |= (1 << 25);
344 break;
346 default:
347 err = -EINVAL;
348 goto out;
350 switch (ch_ctrl->src_ahb1) {
351 case 0:
352 break;
353 case 1:
354 *ctrl |= (1 << 24);
355 break;
357 default:
358 err = -EINVAL;
359 goto out;
361 switch (ch_ctrl->dwidth) {
362 case WIDTH_BYTE:
363 *ctrl &= ~(7 << 21);
364 break;
365 case WIDTH_HWORD:
366 *ctrl &= ~(7 << 21);
367 *ctrl |= (1 << 21);
368 break;
369 case WIDTH_WORD:
370 *ctrl &= ~(7 << 21);
371 *ctrl |= (2 << 21);
372 break;
374 default:
375 err = -EINVAL;
376 goto out;
378 switch (ch_ctrl->swidth) {
379 case WIDTH_BYTE:
380 *ctrl &= ~(7 << 18);
381 break;
382 case WIDTH_HWORD:
383 *ctrl &= ~(7 << 18);
384 *ctrl |= (1 << 18);
385 break;
386 case WIDTH_WORD:
387 *ctrl &= ~(7 << 18);
388 *ctrl |= (2 << 18);
389 break;
391 default:
392 err = -EINVAL;
393 goto out;
395 dbsize = ch_ctrl->dbsize;
396 while (!(dbsize & 1)) {
397 i++;
398 dbsize >>= 1;
400 if (ch_ctrl->dbsize != 1 || i > 8 || i == 1) {
401 err = -EINVAL;
402 goto out;
403 } else if (i > 1)
404 i--;
405 *ctrl &= ~(7 << 15);
406 *ctrl |= (i << 15);
408 sbsize = ch_ctrl->sbsize;
409 while (!(sbsize & 1)) {
410 i++;
411 sbsize >>= 1;
413 if (ch_ctrl->sbsize != 1 || i > 8 || i == 1) {
414 err = -EINVAL;
415 goto out;
416 } else if (i > 1)
417 i--;
418 *ctrl &= ~(7 << 12);
419 *ctrl |= (i << 12);
421 if (ch_ctrl->tr_size > 0x7ff) {
422 err = -E2BIG;
423 goto out;
425 *ctrl &= ~0x7ff;
426 *ctrl |= ch_ctrl->tr_size & 0x7ff;
428 out:
429 return err;
432 EXPORT_SYMBOL_GPL(pnx4008_dma_pack_control);
434 int pnx4008_dma_parse_control(unsigned long ctrl,
435 struct pnx4008_dma_ch_ctrl * ch_ctrl)
437 int err = 0;
439 if (!ch_ctrl) {
440 err = -EINVAL;
441 goto out;
444 ch_ctrl->tr_size = ctrl & 0x7ff;
445 ctrl >>= 12;
447 ch_ctrl->sbsize = 1 << (ctrl & 7);
448 if (ch_ctrl->sbsize > 1)
449 ch_ctrl->sbsize <<= 1;
450 ctrl >>= 3;
452 ch_ctrl->dbsize = 1 << (ctrl & 7);
453 if (ch_ctrl->dbsize > 1)
454 ch_ctrl->dbsize <<= 1;
455 ctrl >>= 3;
457 switch (ctrl & 7) {
458 case 0:
459 ch_ctrl->swidth = WIDTH_BYTE;
460 break;
461 case 1:
462 ch_ctrl->swidth = WIDTH_HWORD;
463 break;
464 case 2:
465 ch_ctrl->swidth = WIDTH_WORD;
466 break;
467 default:
468 err = -EINVAL;
469 goto out;
471 ctrl >>= 3;
473 switch (ctrl & 7) {
474 case 0:
475 ch_ctrl->dwidth = WIDTH_BYTE;
476 break;
477 case 1:
478 ch_ctrl->dwidth = WIDTH_HWORD;
479 break;
480 case 2:
481 ch_ctrl->dwidth = WIDTH_WORD;
482 break;
483 default:
484 err = -EINVAL;
485 goto out;
487 ctrl >>= 3;
489 ch_ctrl->src_ahb1 = ctrl & 1;
490 ctrl >>= 1;
492 ch_ctrl->dest_ahb1 = ctrl & 1;
493 ctrl >>= 1;
495 ch_ctrl->si = ctrl & 1;
496 ctrl >>= 1;
498 ch_ctrl->di = ctrl & 1;
499 ctrl >>= 1;
501 ch_ctrl->priv_mode = ctrl & 1;
502 ctrl >>= 1;
504 ch_ctrl->bufferable = ctrl & 1;
505 ctrl >>= 1;
507 ch_ctrl->cacheable = ctrl & 1;
508 ctrl >>= 1;
510 ch_ctrl->tc_mask = ctrl & 1;
512 out:
513 return err;
516 EXPORT_SYMBOL_GPL(pnx4008_dma_parse_control);
518 int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config * ch_cfg,
519 unsigned long *cfg)
521 int err = 0;
523 if (!cfg || !ch_cfg) {
524 err = -EINVAL;
525 goto out;
528 *cfg = 0;
530 switch (ch_cfg->halt) {
531 case 0:
532 break;
533 case 1:
534 *cfg |= (1 << 18);
535 break;
537 default:
538 err = -EINVAL;
539 goto out;
541 switch (ch_cfg->active) {
542 case 0:
543 break;
544 case 1:
545 *cfg |= (1 << 17);
546 break;
548 default:
549 err = -EINVAL;
550 goto out;
552 switch (ch_cfg->lock) {
553 case 0:
554 break;
555 case 1:
556 *cfg |= (1 << 16);
557 break;
559 default:
560 err = -EINVAL;
561 goto out;
563 switch (ch_cfg->itc) {
564 case 0:
565 break;
566 case 1:
567 *cfg |= (1 << 15);
568 break;
570 default:
571 err = -EINVAL;
572 goto out;
574 switch (ch_cfg->ie) {
575 case 0:
576 break;
577 case 1:
578 *cfg |= (1 << 14);
579 break;
581 default:
582 err = -EINVAL;
583 goto out;
585 switch (ch_cfg->flow_cntrl) {
586 case FC_MEM2MEM_DMA:
587 *cfg &= ~(7 << 11);
588 break;
589 case FC_MEM2PER_DMA:
590 *cfg &= ~(7 << 11);
591 *cfg |= (1 << 11);
592 break;
593 case FC_PER2MEM_DMA:
594 *cfg &= ~(7 << 11);
595 *cfg |= (2 << 11);
596 break;
597 case FC_PER2PER_DMA:
598 *cfg &= ~(7 << 11);
599 *cfg |= (3 << 11);
600 break;
601 case FC_PER2PER_DPER:
602 *cfg &= ~(7 << 11);
603 *cfg |= (4 << 11);
604 break;
605 case FC_MEM2PER_PER:
606 *cfg &= ~(7 << 11);
607 *cfg |= (5 << 11);
608 break;
609 case FC_PER2MEM_PER:
610 *cfg &= ~(7 << 11);
611 *cfg |= (6 << 11);
612 break;
613 case FC_PER2PER_SPER:
614 *cfg |= (7 << 11);
615 break;
617 default:
618 err = -EINVAL;
619 goto out;
621 *cfg &= ~(0x1f << 6);
622 *cfg |= ((ch_cfg->dest_per & 0x1f) << 6);
624 *cfg &= ~(0x1f << 1);
625 *cfg |= ((ch_cfg->src_per & 0x1f) << 1);
627 out:
628 return err;
631 EXPORT_SYMBOL_GPL(pnx4008_dma_pack_config);
633 int pnx4008_dma_parse_config(unsigned long cfg,
634 struct pnx4008_dma_ch_config * ch_cfg)
636 int err = 0;
638 if (!ch_cfg) {
639 err = -EINVAL;
640 goto out;
643 cfg >>= 1;
645 ch_cfg->src_per = cfg & 0x1f;
646 cfg >>= 5;
648 ch_cfg->dest_per = cfg & 0x1f;
649 cfg >>= 5;
651 switch (cfg & 7) {
652 case 0:
653 ch_cfg->flow_cntrl = FC_MEM2MEM_DMA;
654 break;
655 case 1:
656 ch_cfg->flow_cntrl = FC_MEM2PER_DMA;
657 break;
658 case 2:
659 ch_cfg->flow_cntrl = FC_PER2MEM_DMA;
660 break;
661 case 3:
662 ch_cfg->flow_cntrl = FC_PER2PER_DMA;
663 break;
664 case 4:
665 ch_cfg->flow_cntrl = FC_PER2PER_DPER;
666 break;
667 case 5:
668 ch_cfg->flow_cntrl = FC_MEM2PER_PER;
669 break;
670 case 6:
671 ch_cfg->flow_cntrl = FC_PER2MEM_PER;
672 break;
673 case 7:
674 ch_cfg->flow_cntrl = FC_PER2PER_SPER;
676 cfg >>= 3;
678 ch_cfg->ie = cfg & 1;
679 cfg >>= 1;
681 ch_cfg->itc = cfg & 1;
682 cfg >>= 1;
684 ch_cfg->lock = cfg & 1;
685 cfg >>= 1;
687 ch_cfg->active = cfg & 1;
688 cfg >>= 1;
690 ch_cfg->halt = cfg & 1;
692 out:
693 return err;
696 EXPORT_SYMBOL_GPL(pnx4008_dma_parse_config);
698 void pnx4008_dma_split_head_entry(struct pnx4008_dma_config * config,
699 struct pnx4008_dma_ch_ctrl * ctrl)
701 int new_len = ctrl->tr_size, num_entries = 0;
702 int old_len = new_len;
703 int src_width, dest_width, count = 1;
705 switch (ctrl->swidth) {
706 case WIDTH_BYTE:
707 src_width = 1;
708 break;
709 case WIDTH_HWORD:
710 src_width = 2;
711 break;
712 case WIDTH_WORD:
713 src_width = 4;
714 break;
715 default:
716 return;
719 switch (ctrl->dwidth) {
720 case WIDTH_BYTE:
721 dest_width = 1;
722 break;
723 case WIDTH_HWORD:
724 dest_width = 2;
725 break;
726 case WIDTH_WORD:
727 dest_width = 4;
728 break;
729 default:
730 return;
733 while (new_len > 0x7FF) {
734 num_entries++;
735 new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
737 if (num_entries != 0) {
738 struct pnx4008_dma_ll *ll = NULL;
739 config->ch_ctrl &= ~0x7ff;
740 config->ch_ctrl |= new_len;
741 if (!config->is_ll) {
742 config->is_ll = 1;
743 while (num_entries) {
744 if (!ll) {
745 config->ll =
746 pnx4008_alloc_ll_entry(&config->
747 ll_dma);
748 ll = config->ll;
749 } else {
750 ll->next =
751 pnx4008_alloc_ll_entry(&ll->
752 next_dma);
753 ll = ll->next;
756 if (ctrl->si)
757 ll->src_addr =
758 config->src_addr +
759 src_width * new_len * count;
760 else
761 ll->src_addr = config->src_addr;
762 if (ctrl->di)
763 ll->dest_addr =
764 config->dest_addr +
765 dest_width * new_len * count;
766 else
767 ll->dest_addr = config->dest_addr;
768 ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
769 ll->next_dma = 0;
770 ll->next = NULL;
771 num_entries--;
772 count++;
774 } else {
775 struct pnx4008_dma_ll *ll_old = config->ll;
776 unsigned long ll_dma_old = config->ll_dma;
777 while (num_entries) {
778 if (!ll) {
779 config->ll =
780 pnx4008_alloc_ll_entry(&config->
781 ll_dma);
782 ll = config->ll;
783 } else {
784 ll->next =
785 pnx4008_alloc_ll_entry(&ll->
786 next_dma);
787 ll = ll->next;
790 if (ctrl->si)
791 ll->src_addr =
792 config->src_addr +
793 src_width * new_len * count;
794 else
795 ll->src_addr = config->src_addr;
796 if (ctrl->di)
797 ll->dest_addr =
798 config->dest_addr +
799 dest_width * new_len * count;
800 else
801 ll->dest_addr = config->dest_addr;
802 ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
803 ll->next_dma = 0;
804 ll->next = NULL;
805 num_entries--;
806 count++;
808 ll->next_dma = ll_dma_old;
809 ll->next = ll_old;
811 /* adjust last length/tc */
812 ll->ch_ctrl = config->ch_ctrl & (~0x7ff);
813 ll->ch_ctrl |= old_len - new_len * (count - 1);
814 config->ch_ctrl &= 0x7fffffff;
818 EXPORT_SYMBOL_GPL(pnx4008_dma_split_head_entry);
820 void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll * cur_ll,
821 struct pnx4008_dma_ch_ctrl * ctrl)
823 int new_len = ctrl->tr_size, num_entries = 0;
824 int old_len = new_len;
825 int src_width, dest_width, count = 1;
827 switch (ctrl->swidth) {
828 case WIDTH_BYTE:
829 src_width = 1;
830 break;
831 case WIDTH_HWORD:
832 src_width = 2;
833 break;
834 case WIDTH_WORD:
835 src_width = 4;
836 break;
837 default:
838 return;
841 switch (ctrl->dwidth) {
842 case WIDTH_BYTE:
843 dest_width = 1;
844 break;
845 case WIDTH_HWORD:
846 dest_width = 2;
847 break;
848 case WIDTH_WORD:
849 dest_width = 4;
850 break;
851 default:
852 return;
855 while (new_len > 0x7FF) {
856 num_entries++;
857 new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
859 if (num_entries != 0) {
860 struct pnx4008_dma_ll *ll = NULL;
861 cur_ll->ch_ctrl &= ~0x7ff;
862 cur_ll->ch_ctrl |= new_len;
863 if (!cur_ll->next) {
864 while (num_entries) {
865 if (!ll) {
866 cur_ll->next =
867 pnx4008_alloc_ll_entry(&cur_ll->
868 next_dma);
869 ll = cur_ll->next;
870 } else {
871 ll->next =
872 pnx4008_alloc_ll_entry(&ll->
873 next_dma);
874 ll = ll->next;
877 if (ctrl->si)
878 ll->src_addr =
879 cur_ll->src_addr +
880 src_width * new_len * count;
881 else
882 ll->src_addr = cur_ll->src_addr;
883 if (ctrl->di)
884 ll->dest_addr =
885 cur_ll->dest_addr +
886 dest_width * new_len * count;
887 else
888 ll->dest_addr = cur_ll->dest_addr;
889 ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
890 ll->next_dma = 0;
891 ll->next = NULL;
892 num_entries--;
893 count++;
895 } else {
896 struct pnx4008_dma_ll *ll_old = cur_ll->next;
897 unsigned long ll_dma_old = cur_ll->next_dma;
898 while (num_entries) {
899 if (!ll) {
900 cur_ll->next =
901 pnx4008_alloc_ll_entry(&cur_ll->
902 next_dma);
903 ll = cur_ll->next;
904 } else {
905 ll->next =
906 pnx4008_alloc_ll_entry(&ll->
907 next_dma);
908 ll = ll->next;
911 if (ctrl->si)
912 ll->src_addr =
913 cur_ll->src_addr +
914 src_width * new_len * count;
915 else
916 ll->src_addr = cur_ll->src_addr;
917 if (ctrl->di)
918 ll->dest_addr =
919 cur_ll->dest_addr +
920 dest_width * new_len * count;
921 else
922 ll->dest_addr = cur_ll->dest_addr;
923 ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
924 ll->next_dma = 0;
925 ll->next = NULL;
926 num_entries--;
927 count++;
930 ll->next_dma = ll_dma_old;
931 ll->next = ll_old;
933 /* adjust last length/tc */
934 ll->ch_ctrl = cur_ll->ch_ctrl & (~0x7ff);
935 ll->ch_ctrl |= old_len - new_len * (count - 1);
936 cur_ll->ch_ctrl &= 0x7fffffff;
940 EXPORT_SYMBOL_GPL(pnx4008_dma_split_ll_entry);
942 int pnx4008_config_channel(int ch, struct pnx4008_dma_config * config)
944 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
945 return -EINVAL;
947 pnx4008_dma_lock();
948 __raw_writel(config->src_addr, DMAC_Cx_SRC_ADDR(ch));
949 __raw_writel(config->dest_addr, DMAC_Cx_DEST_ADDR(ch));
951 if (config->is_ll)
952 __raw_writel(config->ll_dma, DMAC_Cx_LLI(ch));
953 else
954 __raw_writel(0, DMAC_Cx_LLI(ch));
956 __raw_writel(config->ch_ctrl, DMAC_Cx_CONTROL(ch));
957 __raw_writel(config->ch_cfg, DMAC_Cx_CONFIG(ch));
958 pnx4008_dma_unlock();
960 return 0;
964 EXPORT_SYMBOL_GPL(pnx4008_config_channel);
966 int pnx4008_channel_get_config(int ch, struct pnx4008_dma_config * config)
968 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name || !config)
969 return -EINVAL;
971 pnx4008_dma_lock();
972 config->ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
973 config->ch_ctrl = __raw_readl(DMAC_Cx_CONTROL(ch));
975 config->ll_dma = __raw_readl(DMAC_Cx_LLI(ch));
976 config->is_ll = config->ll_dma ? 1 : 0;
978 config->src_addr = __raw_readl(DMAC_Cx_SRC_ADDR(ch));
979 config->dest_addr = __raw_readl(DMAC_Cx_DEST_ADDR(ch));
980 pnx4008_dma_unlock();
982 return 0;
985 EXPORT_SYMBOL_GPL(pnx4008_channel_get_config);
987 int pnx4008_dma_ch_enable(int ch)
989 unsigned long ch_cfg;
991 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
992 return -EINVAL;
994 pnx4008_dma_lock();
995 ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
996 ch_cfg |= 1;
997 __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
998 pnx4008_dma_unlock();
1000 return 0;
1003 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enable);
1005 int pnx4008_dma_ch_disable(int ch)
1007 unsigned long ch_cfg;
1009 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
1010 return -EINVAL;
1012 pnx4008_dma_lock();
1013 ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
1014 ch_cfg &= ~1;
1015 __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
1016 pnx4008_dma_unlock();
1018 return 0;
1021 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_disable);
1023 int pnx4008_dma_ch_enabled(int ch)
1025 unsigned long ch_cfg;
1027 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
1028 return -EINVAL;
1030 pnx4008_dma_lock();
1031 ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
1032 pnx4008_dma_unlock();
1034 return ch_cfg & 1;
1037 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
1039 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
1041 int i;
1042 unsigned long dint = __raw_readl(DMAC_INT_STAT);
1043 unsigned long tcint = __raw_readl(DMAC_INT_TC_STAT);
1044 unsigned long eint = __raw_readl(DMAC_INT_ERR_STAT);
1045 unsigned long i_bit;
1047 for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
1048 i_bit = 1 << i;
1049 if (dint & i_bit) {
1050 struct dma_channel *channel = &dma_channels[i];
1052 if (channel->name && channel->irq_handler) {
1053 int cause = 0;
1055 if (eint & i_bit)
1056 cause |= DMA_ERR_INT;
1057 if (tcint & i_bit)
1058 cause |= DMA_TC_INT;
1059 channel->irq_handler(i, cause, channel->data);
1060 } else {
1062 * IRQ for an unregistered DMA channel
1064 printk(KERN_WARNING
1065 "spurious IRQ for DMA channel %d\n", i);
1067 if (tcint & i_bit)
1068 __raw_writel(i_bit, DMAC_INT_TC_CLEAR);
1069 if (eint & i_bit)
1070 __raw_writel(i_bit, DMAC_INT_ERR_CLEAR);
1073 return IRQ_HANDLED;
1076 static int __init pnx4008_dma_init(void)
1078 int ret, i;
1080 ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
1081 if (ret) {
1082 printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n");
1083 goto out;
1086 ll_pool.count = 0x4000 / sizeof(struct pnx4008_dma_ll);
1087 ll_pool.cur = ll_pool.vaddr =
1088 dma_alloc_coherent(NULL, ll_pool.count * sizeof(struct pnx4008_dma_ll),
1089 &ll_pool.dma_addr, GFP_KERNEL);
1091 if (!ll_pool.vaddr) {
1092 ret = -ENOMEM;
1093 free_irq(DMA_INT, NULL);
1094 goto out;
1097 for (i = 0; i < ll_pool.count - 1; i++) {
1098 void **addr = ll_pool.vaddr + i * sizeof(struct pnx4008_dma_ll);
1099 *addr = (void *)addr + sizeof(struct pnx4008_dma_ll);
1101 *(long *)(ll_pool.vaddr +
1102 (ll_pool.count - 1) * sizeof(struct pnx4008_dma_ll)) =
1103 (long)ll_pool.vaddr;
1105 __raw_writel(1, DMAC_CONFIG);
1107 out:
1108 return ret;
1110 arch_initcall(pnx4008_dma_init);