ipv4: Minor logic clean-up in ipv4_mtu
[linux-2.6/cjktty.git] / arch / arm / mach-pnx4008 / dma.c
bloba4739e9fb2fbca3e10f9fe59a5107f5d611b58c1
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>
24 #include <linux/io.h>
25 #include <linux/gfp.h>
27 #include <mach/hardware.h>
28 #include <mach/dma.h>
29 #include <asm/dma-mapping.h>
30 #include <mach/clock.h>
32 static struct dma_channel {
33 char *name;
34 void (*irq_handler) (int, int, void *);
35 void *data;
36 struct pnx4008_dma_ll *ll;
37 u32 ll_dma;
38 void *target_addr;
39 int target_id;
40 } dma_channels[MAX_DMA_CHANNELS];
42 static struct ll_pool {
43 void *vaddr;
44 void *cur;
45 dma_addr_t dma_addr;
46 int count;
47 } ll_pool;
49 static DEFINE_SPINLOCK(ll_lock);
51 struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t * ll_dma)
53 struct pnx4008_dma_ll *ll = NULL;
54 unsigned long flags;
56 spin_lock_irqsave(&ll_lock, flags);
57 if (ll_pool.count > 4) { /* can give one more */
58 ll = *(struct pnx4008_dma_ll **) ll_pool.cur;
59 *ll_dma = ll_pool.dma_addr + ((void *)ll - ll_pool.vaddr);
60 *(void **)ll_pool.cur = **(void ***)ll_pool.cur;
61 memset(ll, 0, sizeof(*ll));
62 ll_pool.count--;
64 spin_unlock_irqrestore(&ll_lock, flags);
66 return ll;
69 EXPORT_SYMBOL_GPL(pnx4008_alloc_ll_entry);
71 void pnx4008_free_ll_entry(struct pnx4008_dma_ll * ll, dma_addr_t ll_dma)
73 unsigned long flags;
75 if (ll) {
76 if ((unsigned long)((long)ll - (long)ll_pool.vaddr) > 0x4000) {
77 printk(KERN_ERR "Trying to free entry not allocated by DMA\n");
78 BUG();
81 if (ll->flags & DMA_BUFFER_ALLOCATED)
82 ll->free(ll->alloc_data);
84 spin_lock_irqsave(&ll_lock, flags);
85 *(long *)ll = *(long *)ll_pool.cur;
86 *(long *)ll_pool.cur = (long)ll;
87 ll_pool.count++;
88 spin_unlock_irqrestore(&ll_lock, flags);
92 EXPORT_SYMBOL_GPL(pnx4008_free_ll_entry);
94 void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll * ll)
96 struct pnx4008_dma_ll *ptr;
97 u32 dma;
99 while (ll) {
100 dma = ll->next_dma;
101 ptr = ll->next;
102 pnx4008_free_ll_entry(ll, ll_dma);
104 ll_dma = dma;
105 ll = ptr;
109 EXPORT_SYMBOL_GPL(pnx4008_free_ll);
111 static int dma_channels_requested = 0;
113 static inline void dma_increment_usage(void)
115 if (!dma_channels_requested++) {
116 struct clk *clk = clk_get(0, "dma_ck");
117 if (!IS_ERR(clk)) {
118 clk_set_rate(clk, 1);
119 clk_put(clk);
121 pnx4008_config_dma(-1, -1, 1);
124 static inline void dma_decrement_usage(void)
126 if (!--dma_channels_requested) {
127 struct clk *clk = clk_get(0, "dma_ck");
128 if (!IS_ERR(clk)) {
129 clk_set_rate(clk, 0);
130 clk_put(clk);
132 pnx4008_config_dma(-1, -1, 0);
137 static DEFINE_SPINLOCK(dma_lock);
139 static inline void pnx4008_dma_lock(void)
141 spin_lock_irq(&dma_lock);
144 static inline void pnx4008_dma_unlock(void)
146 spin_unlock_irq(&dma_lock);
149 #define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
151 int pnx4008_request_channel(char *name, int ch,
152 void (*irq_handler) (int, int, void *), void *data)
154 int i, found = 0;
156 /* basic sanity checks */
157 if (!name || (ch != -1 && !VALID_CHANNEL(ch)))
158 return -EINVAL;
160 pnx4008_dma_lock();
162 /* try grabbing a DMA channel with the requested priority */
163 for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
164 if (!dma_channels[i].name && (ch == -1 || ch == i)) {
165 found = 1;
166 break;
170 if (found) {
171 dma_increment_usage();
172 dma_channels[i].name = name;
173 dma_channels[i].irq_handler = irq_handler;
174 dma_channels[i].data = data;
175 dma_channels[i].ll = NULL;
176 dma_channels[i].ll_dma = 0;
177 } else {
178 printk(KERN_WARNING "No more available DMA channels for %s\n",
179 name);
180 i = -ENODEV;
183 pnx4008_dma_unlock();
184 return i;
187 EXPORT_SYMBOL_GPL(pnx4008_request_channel);
189 void pnx4008_free_channel(int ch)
191 if (!dma_channels[ch].name) {
192 printk(KERN_CRIT
193 "%s: trying to free channel %d which is already freed\n",
194 __func__, ch);
195 return;
198 pnx4008_dma_lock();
199 pnx4008_free_ll(dma_channels[ch].ll_dma, dma_channels[ch].ll);
200 dma_channels[ch].ll = NULL;
201 dma_decrement_usage();
203 dma_channels[ch].name = NULL;
204 pnx4008_dma_unlock();
207 EXPORT_SYMBOL_GPL(pnx4008_free_channel);
209 int pnx4008_config_dma(int ahb_m1_be, int ahb_m2_be, int enable)
211 unsigned long dma_cfg = __raw_readl(DMAC_CONFIG);
213 switch (ahb_m1_be) {
214 case 0:
215 dma_cfg &= ~(1 << 1);
216 break;
217 case 1:
218 dma_cfg |= (1 << 1);
219 break;
220 default:
221 break;
224 switch (ahb_m2_be) {
225 case 0:
226 dma_cfg &= ~(1 << 2);
227 break;
228 case 1:
229 dma_cfg |= (1 << 2);
230 break;
231 default:
232 break;
235 switch (enable) {
236 case 0:
237 dma_cfg &= ~(1 << 0);
238 break;
239 case 1:
240 dma_cfg |= (1 << 0);
241 break;
242 default:
243 break;
246 pnx4008_dma_lock();
247 __raw_writel(dma_cfg, DMAC_CONFIG);
248 pnx4008_dma_unlock();
250 return 0;
253 EXPORT_SYMBOL_GPL(pnx4008_config_dma);
255 int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl * ch_ctrl,
256 unsigned long *ctrl)
258 int i = 0, dbsize, sbsize, err = 0;
260 if (!ctrl || !ch_ctrl) {
261 err = -EINVAL;
262 goto out;
265 *ctrl = 0;
267 switch (ch_ctrl->tc_mask) {
268 case 0:
269 break;
270 case 1:
271 *ctrl |= (1 << 31);
272 break;
274 default:
275 err = -EINVAL;
276 goto out;
279 switch (ch_ctrl->cacheable) {
280 case 0:
281 break;
282 case 1:
283 *ctrl |= (1 << 30);
284 break;
286 default:
287 err = -EINVAL;
288 goto out;
290 switch (ch_ctrl->bufferable) {
291 case 0:
292 break;
293 case 1:
294 *ctrl |= (1 << 29);
295 break;
297 default:
298 err = -EINVAL;
299 goto out;
301 switch (ch_ctrl->priv_mode) {
302 case 0:
303 break;
304 case 1:
305 *ctrl |= (1 << 28);
306 break;
308 default:
309 err = -EINVAL;
310 goto out;
312 switch (ch_ctrl->di) {
313 case 0:
314 break;
315 case 1:
316 *ctrl |= (1 << 27);
317 break;
319 default:
320 err = -EINVAL;
321 goto out;
323 switch (ch_ctrl->si) {
324 case 0:
325 break;
326 case 1:
327 *ctrl |= (1 << 26);
328 break;
330 default:
331 err = -EINVAL;
332 goto out;
334 switch (ch_ctrl->dest_ahb1) {
335 case 0:
336 break;
337 case 1:
338 *ctrl |= (1 << 25);
339 break;
341 default:
342 err = -EINVAL;
343 goto out;
345 switch (ch_ctrl->src_ahb1) {
346 case 0:
347 break;
348 case 1:
349 *ctrl |= (1 << 24);
350 break;
352 default:
353 err = -EINVAL;
354 goto out;
356 switch (ch_ctrl->dwidth) {
357 case WIDTH_BYTE:
358 *ctrl &= ~(7 << 21);
359 break;
360 case WIDTH_HWORD:
361 *ctrl &= ~(7 << 21);
362 *ctrl |= (1 << 21);
363 break;
364 case WIDTH_WORD:
365 *ctrl &= ~(7 << 21);
366 *ctrl |= (2 << 21);
367 break;
369 default:
370 err = -EINVAL;
371 goto out;
373 switch (ch_ctrl->swidth) {
374 case WIDTH_BYTE:
375 *ctrl &= ~(7 << 18);
376 break;
377 case WIDTH_HWORD:
378 *ctrl &= ~(7 << 18);
379 *ctrl |= (1 << 18);
380 break;
381 case WIDTH_WORD:
382 *ctrl &= ~(7 << 18);
383 *ctrl |= (2 << 18);
384 break;
386 default:
387 err = -EINVAL;
388 goto out;
390 dbsize = ch_ctrl->dbsize;
391 while (!(dbsize & 1)) {
392 i++;
393 dbsize >>= 1;
395 if (ch_ctrl->dbsize != 1 || i > 8 || i == 1) {
396 err = -EINVAL;
397 goto out;
398 } else if (i > 1)
399 i--;
400 *ctrl &= ~(7 << 15);
401 *ctrl |= (i << 15);
403 sbsize = ch_ctrl->sbsize;
404 while (!(sbsize & 1)) {
405 i++;
406 sbsize >>= 1;
408 if (ch_ctrl->sbsize != 1 || i > 8 || i == 1) {
409 err = -EINVAL;
410 goto out;
411 } else if (i > 1)
412 i--;
413 *ctrl &= ~(7 << 12);
414 *ctrl |= (i << 12);
416 if (ch_ctrl->tr_size > 0x7ff) {
417 err = -E2BIG;
418 goto out;
420 *ctrl &= ~0x7ff;
421 *ctrl |= ch_ctrl->tr_size & 0x7ff;
423 out:
424 return err;
427 EXPORT_SYMBOL_GPL(pnx4008_dma_pack_control);
429 int pnx4008_dma_parse_control(unsigned long ctrl,
430 struct pnx4008_dma_ch_ctrl * ch_ctrl)
432 int err = 0;
434 if (!ch_ctrl) {
435 err = -EINVAL;
436 goto out;
439 ch_ctrl->tr_size = ctrl & 0x7ff;
440 ctrl >>= 12;
442 ch_ctrl->sbsize = 1 << (ctrl & 7);
443 if (ch_ctrl->sbsize > 1)
444 ch_ctrl->sbsize <<= 1;
445 ctrl >>= 3;
447 ch_ctrl->dbsize = 1 << (ctrl & 7);
448 if (ch_ctrl->dbsize > 1)
449 ch_ctrl->dbsize <<= 1;
450 ctrl >>= 3;
452 switch (ctrl & 7) {
453 case 0:
454 ch_ctrl->swidth = WIDTH_BYTE;
455 break;
456 case 1:
457 ch_ctrl->swidth = WIDTH_HWORD;
458 break;
459 case 2:
460 ch_ctrl->swidth = WIDTH_WORD;
461 break;
462 default:
463 err = -EINVAL;
464 goto out;
466 ctrl >>= 3;
468 switch (ctrl & 7) {
469 case 0:
470 ch_ctrl->dwidth = WIDTH_BYTE;
471 break;
472 case 1:
473 ch_ctrl->dwidth = WIDTH_HWORD;
474 break;
475 case 2:
476 ch_ctrl->dwidth = WIDTH_WORD;
477 break;
478 default:
479 err = -EINVAL;
480 goto out;
482 ctrl >>= 3;
484 ch_ctrl->src_ahb1 = ctrl & 1;
485 ctrl >>= 1;
487 ch_ctrl->dest_ahb1 = ctrl & 1;
488 ctrl >>= 1;
490 ch_ctrl->si = ctrl & 1;
491 ctrl >>= 1;
493 ch_ctrl->di = ctrl & 1;
494 ctrl >>= 1;
496 ch_ctrl->priv_mode = ctrl & 1;
497 ctrl >>= 1;
499 ch_ctrl->bufferable = ctrl & 1;
500 ctrl >>= 1;
502 ch_ctrl->cacheable = ctrl & 1;
503 ctrl >>= 1;
505 ch_ctrl->tc_mask = ctrl & 1;
507 out:
508 return err;
511 EXPORT_SYMBOL_GPL(pnx4008_dma_parse_control);
513 int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config * ch_cfg,
514 unsigned long *cfg)
516 int err = 0;
518 if (!cfg || !ch_cfg) {
519 err = -EINVAL;
520 goto out;
523 *cfg = 0;
525 switch (ch_cfg->halt) {
526 case 0:
527 break;
528 case 1:
529 *cfg |= (1 << 18);
530 break;
532 default:
533 err = -EINVAL;
534 goto out;
536 switch (ch_cfg->active) {
537 case 0:
538 break;
539 case 1:
540 *cfg |= (1 << 17);
541 break;
543 default:
544 err = -EINVAL;
545 goto out;
547 switch (ch_cfg->lock) {
548 case 0:
549 break;
550 case 1:
551 *cfg |= (1 << 16);
552 break;
554 default:
555 err = -EINVAL;
556 goto out;
558 switch (ch_cfg->itc) {
559 case 0:
560 break;
561 case 1:
562 *cfg |= (1 << 15);
563 break;
565 default:
566 err = -EINVAL;
567 goto out;
569 switch (ch_cfg->ie) {
570 case 0:
571 break;
572 case 1:
573 *cfg |= (1 << 14);
574 break;
576 default:
577 err = -EINVAL;
578 goto out;
580 switch (ch_cfg->flow_cntrl) {
581 case FC_MEM2MEM_DMA:
582 *cfg &= ~(7 << 11);
583 break;
584 case FC_MEM2PER_DMA:
585 *cfg &= ~(7 << 11);
586 *cfg |= (1 << 11);
587 break;
588 case FC_PER2MEM_DMA:
589 *cfg &= ~(7 << 11);
590 *cfg |= (2 << 11);
591 break;
592 case FC_PER2PER_DMA:
593 *cfg &= ~(7 << 11);
594 *cfg |= (3 << 11);
595 break;
596 case FC_PER2PER_DPER:
597 *cfg &= ~(7 << 11);
598 *cfg |= (4 << 11);
599 break;
600 case FC_MEM2PER_PER:
601 *cfg &= ~(7 << 11);
602 *cfg |= (5 << 11);
603 break;
604 case FC_PER2MEM_PER:
605 *cfg &= ~(7 << 11);
606 *cfg |= (6 << 11);
607 break;
608 case FC_PER2PER_SPER:
609 *cfg |= (7 << 11);
610 break;
612 default:
613 err = -EINVAL;
614 goto out;
616 *cfg &= ~(0x1f << 6);
617 *cfg |= ((ch_cfg->dest_per & 0x1f) << 6);
619 *cfg &= ~(0x1f << 1);
620 *cfg |= ((ch_cfg->src_per & 0x1f) << 1);
622 out:
623 return err;
626 EXPORT_SYMBOL_GPL(pnx4008_dma_pack_config);
628 int pnx4008_dma_parse_config(unsigned long cfg,
629 struct pnx4008_dma_ch_config * ch_cfg)
631 int err = 0;
633 if (!ch_cfg) {
634 err = -EINVAL;
635 goto out;
638 cfg >>= 1;
640 ch_cfg->src_per = cfg & 0x1f;
641 cfg >>= 5;
643 ch_cfg->dest_per = cfg & 0x1f;
644 cfg >>= 5;
646 switch (cfg & 7) {
647 case 0:
648 ch_cfg->flow_cntrl = FC_MEM2MEM_DMA;
649 break;
650 case 1:
651 ch_cfg->flow_cntrl = FC_MEM2PER_DMA;
652 break;
653 case 2:
654 ch_cfg->flow_cntrl = FC_PER2MEM_DMA;
655 break;
656 case 3:
657 ch_cfg->flow_cntrl = FC_PER2PER_DMA;
658 break;
659 case 4:
660 ch_cfg->flow_cntrl = FC_PER2PER_DPER;
661 break;
662 case 5:
663 ch_cfg->flow_cntrl = FC_MEM2PER_PER;
664 break;
665 case 6:
666 ch_cfg->flow_cntrl = FC_PER2MEM_PER;
667 break;
668 case 7:
669 ch_cfg->flow_cntrl = FC_PER2PER_SPER;
671 cfg >>= 3;
673 ch_cfg->ie = cfg & 1;
674 cfg >>= 1;
676 ch_cfg->itc = cfg & 1;
677 cfg >>= 1;
679 ch_cfg->lock = cfg & 1;
680 cfg >>= 1;
682 ch_cfg->active = cfg & 1;
683 cfg >>= 1;
685 ch_cfg->halt = cfg & 1;
687 out:
688 return err;
691 EXPORT_SYMBOL_GPL(pnx4008_dma_parse_config);
693 void pnx4008_dma_split_head_entry(struct pnx4008_dma_config * config,
694 struct pnx4008_dma_ch_ctrl * ctrl)
696 int new_len = ctrl->tr_size, num_entries = 0;
697 int old_len = new_len;
698 int src_width, dest_width, count = 1;
700 switch (ctrl->swidth) {
701 case WIDTH_BYTE:
702 src_width = 1;
703 break;
704 case WIDTH_HWORD:
705 src_width = 2;
706 break;
707 case WIDTH_WORD:
708 src_width = 4;
709 break;
710 default:
711 return;
714 switch (ctrl->dwidth) {
715 case WIDTH_BYTE:
716 dest_width = 1;
717 break;
718 case WIDTH_HWORD:
719 dest_width = 2;
720 break;
721 case WIDTH_WORD:
722 dest_width = 4;
723 break;
724 default:
725 return;
728 while (new_len > 0x7FF) {
729 num_entries++;
730 new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
732 if (num_entries != 0) {
733 struct pnx4008_dma_ll *ll = NULL;
734 config->ch_ctrl &= ~0x7ff;
735 config->ch_ctrl |= new_len;
736 if (!config->is_ll) {
737 config->is_ll = 1;
738 while (num_entries) {
739 if (!ll) {
740 config->ll =
741 pnx4008_alloc_ll_entry(&config->
742 ll_dma);
743 ll = config->ll;
744 } else {
745 ll->next =
746 pnx4008_alloc_ll_entry(&ll->
747 next_dma);
748 ll = ll->next;
751 if (ctrl->si)
752 ll->src_addr =
753 config->src_addr +
754 src_width * new_len * count;
755 else
756 ll->src_addr = config->src_addr;
757 if (ctrl->di)
758 ll->dest_addr =
759 config->dest_addr +
760 dest_width * new_len * count;
761 else
762 ll->dest_addr = config->dest_addr;
763 ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
764 ll->next_dma = 0;
765 ll->next = NULL;
766 num_entries--;
767 count++;
769 } else {
770 struct pnx4008_dma_ll *ll_old = config->ll;
771 unsigned long ll_dma_old = config->ll_dma;
772 while (num_entries) {
773 if (!ll) {
774 config->ll =
775 pnx4008_alloc_ll_entry(&config->
776 ll_dma);
777 ll = config->ll;
778 } else {
779 ll->next =
780 pnx4008_alloc_ll_entry(&ll->
781 next_dma);
782 ll = ll->next;
785 if (ctrl->si)
786 ll->src_addr =
787 config->src_addr +
788 src_width * new_len * count;
789 else
790 ll->src_addr = config->src_addr;
791 if (ctrl->di)
792 ll->dest_addr =
793 config->dest_addr +
794 dest_width * new_len * count;
795 else
796 ll->dest_addr = config->dest_addr;
797 ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
798 ll->next_dma = 0;
799 ll->next = NULL;
800 num_entries--;
801 count++;
803 ll->next_dma = ll_dma_old;
804 ll->next = ll_old;
806 /* adjust last length/tc */
807 ll->ch_ctrl = config->ch_ctrl & (~0x7ff);
808 ll->ch_ctrl |= old_len - new_len * (count - 1);
809 config->ch_ctrl &= 0x7fffffff;
813 EXPORT_SYMBOL_GPL(pnx4008_dma_split_head_entry);
815 void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll * cur_ll,
816 struct pnx4008_dma_ch_ctrl * ctrl)
818 int new_len = ctrl->tr_size, num_entries = 0;
819 int old_len = new_len;
820 int src_width, dest_width, count = 1;
822 switch (ctrl->swidth) {
823 case WIDTH_BYTE:
824 src_width = 1;
825 break;
826 case WIDTH_HWORD:
827 src_width = 2;
828 break;
829 case WIDTH_WORD:
830 src_width = 4;
831 break;
832 default:
833 return;
836 switch (ctrl->dwidth) {
837 case WIDTH_BYTE:
838 dest_width = 1;
839 break;
840 case WIDTH_HWORD:
841 dest_width = 2;
842 break;
843 case WIDTH_WORD:
844 dest_width = 4;
845 break;
846 default:
847 return;
850 while (new_len > 0x7FF) {
851 num_entries++;
852 new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
854 if (num_entries != 0) {
855 struct pnx4008_dma_ll *ll = NULL;
856 cur_ll->ch_ctrl &= ~0x7ff;
857 cur_ll->ch_ctrl |= new_len;
858 if (!cur_ll->next) {
859 while (num_entries) {
860 if (!ll) {
861 cur_ll->next =
862 pnx4008_alloc_ll_entry(&cur_ll->
863 next_dma);
864 ll = cur_ll->next;
865 } else {
866 ll->next =
867 pnx4008_alloc_ll_entry(&ll->
868 next_dma);
869 ll = ll->next;
872 if (ctrl->si)
873 ll->src_addr =
874 cur_ll->src_addr +
875 src_width * new_len * count;
876 else
877 ll->src_addr = cur_ll->src_addr;
878 if (ctrl->di)
879 ll->dest_addr =
880 cur_ll->dest_addr +
881 dest_width * new_len * count;
882 else
883 ll->dest_addr = cur_ll->dest_addr;
884 ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
885 ll->next_dma = 0;
886 ll->next = NULL;
887 num_entries--;
888 count++;
890 } else {
891 struct pnx4008_dma_ll *ll_old = cur_ll->next;
892 unsigned long ll_dma_old = cur_ll->next_dma;
893 while (num_entries) {
894 if (!ll) {
895 cur_ll->next =
896 pnx4008_alloc_ll_entry(&cur_ll->
897 next_dma);
898 ll = cur_ll->next;
899 } else {
900 ll->next =
901 pnx4008_alloc_ll_entry(&ll->
902 next_dma);
903 ll = ll->next;
906 if (ctrl->si)
907 ll->src_addr =
908 cur_ll->src_addr +
909 src_width * new_len * count;
910 else
911 ll->src_addr = cur_ll->src_addr;
912 if (ctrl->di)
913 ll->dest_addr =
914 cur_ll->dest_addr +
915 dest_width * new_len * count;
916 else
917 ll->dest_addr = cur_ll->dest_addr;
918 ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
919 ll->next_dma = 0;
920 ll->next = NULL;
921 num_entries--;
922 count++;
925 ll->next_dma = ll_dma_old;
926 ll->next = ll_old;
928 /* adjust last length/tc */
929 ll->ch_ctrl = cur_ll->ch_ctrl & (~0x7ff);
930 ll->ch_ctrl |= old_len - new_len * (count - 1);
931 cur_ll->ch_ctrl &= 0x7fffffff;
935 EXPORT_SYMBOL_GPL(pnx4008_dma_split_ll_entry);
937 int pnx4008_config_channel(int ch, struct pnx4008_dma_config * config)
939 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
940 return -EINVAL;
942 pnx4008_dma_lock();
943 __raw_writel(config->src_addr, DMAC_Cx_SRC_ADDR(ch));
944 __raw_writel(config->dest_addr, DMAC_Cx_DEST_ADDR(ch));
946 if (config->is_ll)
947 __raw_writel(config->ll_dma, DMAC_Cx_LLI(ch));
948 else
949 __raw_writel(0, DMAC_Cx_LLI(ch));
951 __raw_writel(config->ch_ctrl, DMAC_Cx_CONTROL(ch));
952 __raw_writel(config->ch_cfg, DMAC_Cx_CONFIG(ch));
953 pnx4008_dma_unlock();
955 return 0;
959 EXPORT_SYMBOL_GPL(pnx4008_config_channel);
961 int pnx4008_channel_get_config(int ch, struct pnx4008_dma_config * config)
963 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name || !config)
964 return -EINVAL;
966 pnx4008_dma_lock();
967 config->ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
968 config->ch_ctrl = __raw_readl(DMAC_Cx_CONTROL(ch));
970 config->ll_dma = __raw_readl(DMAC_Cx_LLI(ch));
971 config->is_ll = config->ll_dma ? 1 : 0;
973 config->src_addr = __raw_readl(DMAC_Cx_SRC_ADDR(ch));
974 config->dest_addr = __raw_readl(DMAC_Cx_DEST_ADDR(ch));
975 pnx4008_dma_unlock();
977 return 0;
980 EXPORT_SYMBOL_GPL(pnx4008_channel_get_config);
982 int pnx4008_dma_ch_enable(int ch)
984 unsigned long ch_cfg;
986 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
987 return -EINVAL;
989 pnx4008_dma_lock();
990 ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
991 ch_cfg |= 1;
992 __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
993 pnx4008_dma_unlock();
995 return 0;
998 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enable);
1000 int pnx4008_dma_ch_disable(int ch)
1002 unsigned long ch_cfg;
1004 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
1005 return -EINVAL;
1007 pnx4008_dma_lock();
1008 ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
1009 ch_cfg &= ~1;
1010 __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
1011 pnx4008_dma_unlock();
1013 return 0;
1016 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_disable);
1018 int pnx4008_dma_ch_enabled(int ch)
1020 unsigned long ch_cfg;
1022 if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
1023 return -EINVAL;
1025 pnx4008_dma_lock();
1026 ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
1027 pnx4008_dma_unlock();
1029 return ch_cfg & 1;
1032 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
1034 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
1036 int i;
1037 unsigned long dint = __raw_readl(DMAC_INT_STAT);
1038 unsigned long tcint = __raw_readl(DMAC_INT_TC_STAT);
1039 unsigned long eint = __raw_readl(DMAC_INT_ERR_STAT);
1040 unsigned long i_bit;
1042 for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
1043 i_bit = 1 << i;
1044 if (dint & i_bit) {
1045 struct dma_channel *channel = &dma_channels[i];
1047 if (channel->name && channel->irq_handler) {
1048 int cause = 0;
1050 if (eint & i_bit)
1051 cause |= DMA_ERR_INT;
1052 if (tcint & i_bit)
1053 cause |= DMA_TC_INT;
1054 channel->irq_handler(i, cause, channel->data);
1055 } else {
1057 * IRQ for an unregistered DMA channel
1059 printk(KERN_WARNING
1060 "spurious IRQ for DMA channel %d\n", i);
1062 if (tcint & i_bit)
1063 __raw_writel(i_bit, DMAC_INT_TC_CLEAR);
1064 if (eint & i_bit)
1065 __raw_writel(i_bit, DMAC_INT_ERR_CLEAR);
1068 return IRQ_HANDLED;
1071 static int __init pnx4008_dma_init(void)
1073 int ret, i;
1075 ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
1076 if (ret) {
1077 printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n");
1078 goto out;
1081 ll_pool.count = 0x4000 / sizeof(struct pnx4008_dma_ll);
1082 ll_pool.cur = ll_pool.vaddr =
1083 dma_alloc_coherent(NULL, ll_pool.count * sizeof(struct pnx4008_dma_ll),
1084 &ll_pool.dma_addr, GFP_KERNEL);
1086 if (!ll_pool.vaddr) {
1087 ret = -ENOMEM;
1088 free_irq(DMA_INT, NULL);
1089 goto out;
1092 for (i = 0; i < ll_pool.count - 1; i++) {
1093 void **addr = ll_pool.vaddr + i * sizeof(struct pnx4008_dma_ll);
1094 *addr = (void *)addr + sizeof(struct pnx4008_dma_ll);
1096 *(long *)(ll_pool.vaddr +
1097 (ll_pool.count - 1) * sizeof(struct pnx4008_dma_ll)) =
1098 (long)ll_pool.vaddr;
1100 __raw_writel(1, DMAC_CONFIG);
1102 out:
1103 return ret;
1105 arch_initcall(pnx4008_dma_init);