Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / arch / arm / mach-pnx4008 / dma.c
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
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>
26
27 #include <asm/system.h>
28 #include <mach/hardware.h>
29 #include <mach/dma.h>
30 #include <asm/dma-mapping.h>
31 #include <mach/clock.h>
32
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];
42
43 static struct ll_pool {
44         void *vaddr;
45         void *cur;
46         dma_addr_t dma_addr;
47         int count;
48 } ll_pool;
49
50 static DEFINE_SPINLOCK(ll_lock);
51
52 struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t * ll_dma)
53 {
54         struct pnx4008_dma_ll *ll = NULL;
55         unsigned long flags;
56
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--;
64         }
65         spin_unlock_irqrestore(&ll_lock, flags);
66
67         return ll;
68 }
69
70 EXPORT_SYMBOL_GPL(pnx4008_alloc_ll_entry);
71
72 void pnx4008_free_ll_entry(struct pnx4008_dma_ll * ll, dma_addr_t ll_dma)
73 {
74         unsigned long flags;
75
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();
80                 }
81
82                 if (ll->flags & DMA_BUFFER_ALLOCATED)
83                         ll->free(ll->alloc_data);
84
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);
90         }
91 }
92
93 EXPORT_SYMBOL_GPL(pnx4008_free_ll_entry);
94
95 void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll * ll)
96 {
97         struct pnx4008_dma_ll *ptr;
98         u32 dma;
99
100         while (ll) {
101                 dma = ll->next_dma;
102                 ptr = ll->next;
103                 pnx4008_free_ll_entry(ll, ll_dma);
104
105                 ll_dma = dma;
106                 ll = ptr;
107         }
108 }
109
110 EXPORT_SYMBOL_GPL(pnx4008_free_ll);
111
112 static int dma_channels_requested = 0;
113
114 static inline void dma_increment_usage(void)
115 {
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);
121                 }
122                 pnx4008_config_dma(-1, -1, 1);
123         }
124 }
125 static inline void dma_decrement_usage(void)
126 {
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);
132                 }
133                 pnx4008_config_dma(-1, -1, 0);
134
135         }
136 }
137
138 static DEFINE_SPINLOCK(dma_lock);
139
140 static inline void pnx4008_dma_lock(void)
141 {
142         spin_lock_irq(&dma_lock);
143 }
144
145 static inline void pnx4008_dma_unlock(void)
146 {
147         spin_unlock_irq(&dma_lock);
148 }
149
150 #define VALID_CHANNEL(c)        (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
151
152 int pnx4008_request_channel(char *name, int ch,
153                             void (*irq_handler) (int, int, void *), void *data)
154 {
155         int i, found = 0;
156
157         /* basic sanity checks */
158         if (!name || (ch != -1 && !VALID_CHANNEL(ch)))
159                 return -EINVAL;
160
161         pnx4008_dma_lock();
162
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;
168                 }
169         }
170
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;
182         }
183
184         pnx4008_dma_unlock();
185         return i;
186 }
187
188 EXPORT_SYMBOL_GPL(pnx4008_request_channel);
189
190 void pnx4008_free_channel(int ch)
191 {
192         if (!dma_channels[ch].name) {
193                 printk(KERN_CRIT
194                        "%s: trying to free channel %d which is already freed\n",
195                        __func__, ch);
196                 return;
197         }
198
199         pnx4008_dma_lock();
200         pnx4008_free_ll(dma_channels[ch].ll_dma, dma_channels[ch].ll);
201         dma_channels[ch].ll = NULL;
202         dma_decrement_usage();
203
204         dma_channels[ch].name = NULL;
205         pnx4008_dma_unlock();
206 }
207
208 EXPORT_SYMBOL_GPL(pnx4008_free_channel);
209
210 int pnx4008_config_dma(int ahb_m1_be, int ahb_m2_be, int enable)
211 {
212         unsigned long dma_cfg = __raw_readl(DMAC_CONFIG);
213
214         switch (ahb_m1_be) {
215         case 0:
216                 dma_cfg &= ~(1 << 1);
217                 break;
218         case 1:
219                 dma_cfg |= (1 << 1);
220                 break;
221         default:
222                 break;
223         }
224
225         switch (ahb_m2_be) {
226         case 0:
227                 dma_cfg &= ~(1 << 2);
228                 break;
229         case 1:
230                 dma_cfg |= (1 << 2);
231                 break;
232         default:
233                 break;
234         }
235
236         switch (enable) {
237         case 0:
238                 dma_cfg &= ~(1 << 0);
239                 break;
240         case 1:
241                 dma_cfg |= (1 << 0);
242                 break;
243         default:
244                 break;
245         }
246
247         pnx4008_dma_lock();
248         __raw_writel(dma_cfg, DMAC_CONFIG);
249         pnx4008_dma_unlock();
250
251         return 0;
252 }
253
254 EXPORT_SYMBOL_GPL(pnx4008_config_dma);
255
256 int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl * ch_ctrl,
257                              unsigned long *ctrl)
258 {
259         int i = 0, dbsize, sbsize, err = 0;
260
261         if (!ctrl || !ch_ctrl) {
262                 err = -EINVAL;
263                 goto out;
264         }
265
266         *ctrl = 0;
267
268         switch (ch_ctrl->tc_mask) {
269         case 0:
270                 break;
271         case 1:
272                 *ctrl |= (1 << 31);
273                 break;
274
275         default:
276                 err = -EINVAL;
277                 goto out;
278         }
279
280         switch (ch_ctrl->cacheable) {
281         case 0:
282                 break;
283         case 1:
284                 *ctrl |= (1 << 30);
285                 break;
286
287         default:
288                 err = -EINVAL;
289                 goto out;
290         }
291         switch (ch_ctrl->bufferable) {
292         case 0:
293                 break;
294         case 1:
295                 *ctrl |= (1 << 29);
296                 break;
297
298         default:
299                 err = -EINVAL;
300                 goto out;
301         }
302         switch (ch_ctrl->priv_mode) {
303         case 0:
304                 break;
305         case 1:
306                 *ctrl |= (1 << 28);
307                 break;
308
309         default:
310                 err = -EINVAL;
311                 goto out;
312         }
313         switch (ch_ctrl->di) {
314         case 0:
315                 break;
316         case 1:
317                 *ctrl |= (1 << 27);
318                 break;
319
320         default:
321                 err = -EINVAL;
322                 goto out;
323         }
324         switch (ch_ctrl->si) {
325         case 0:
326                 break;
327         case 1:
328                 *ctrl |= (1 << 26);
329                 break;
330
331         default:
332                 err = -EINVAL;
333                 goto out;
334         }
335         switch (ch_ctrl->dest_ahb1) {
336         case 0:
337                 break;
338         case 1:
339                 *ctrl |= (1 << 25);
340                 break;
341
342         default:
343                 err = -EINVAL;
344                 goto out;
345         }
346         switch (ch_ctrl->src_ahb1) {
347         case 0:
348                 break;
349         case 1:
350                 *ctrl |= (1 << 24);
351                 break;
352
353         default:
354                 err = -EINVAL;
355                 goto out;
356         }
357         switch (ch_ctrl->dwidth) {
358         case WIDTH_BYTE:
359                 *ctrl &= ~(7 << 21);
360                 break;
361         case WIDTH_HWORD:
362                 *ctrl &= ~(7 << 21);
363                 *ctrl |= (1 << 21);
364                 break;
365         case WIDTH_WORD:
366                 *ctrl &= ~(7 << 21);
367                 *ctrl |= (2 << 21);
368                 break;
369
370         default:
371                 err = -EINVAL;
372                 goto out;
373         }
374         switch (ch_ctrl->swidth) {
375         case WIDTH_BYTE:
376                 *ctrl &= ~(7 << 18);
377                 break;
378         case WIDTH_HWORD:
379                 *ctrl &= ~(7 << 18);
380                 *ctrl |= (1 << 18);
381                 break;
382         case WIDTH_WORD:
383                 *ctrl &= ~(7 << 18);
384                 *ctrl |= (2 << 18);
385                 break;
386
387         default:
388                 err = -EINVAL;
389                 goto out;
390         }
391         dbsize = ch_ctrl->dbsize;
392         while (!(dbsize & 1)) {
393                 i++;
394                 dbsize >>= 1;
395         }
396         if (ch_ctrl->dbsize != 1 || i > 8 || i == 1) {
397                 err = -EINVAL;
398                 goto out;
399         } else if (i > 1)
400                 i--;
401         *ctrl &= ~(7 << 15);
402         *ctrl |= (i << 15);
403
404         sbsize = ch_ctrl->sbsize;
405         while (!(sbsize & 1)) {
406                 i++;
407                 sbsize >>= 1;
408         }
409         if (ch_ctrl->sbsize != 1 || i > 8 || i == 1) {
410                 err = -EINVAL;
411                 goto out;
412         } else if (i > 1)
413                 i--;
414         *ctrl &= ~(7 << 12);
415         *ctrl |= (i << 12);
416
417         if (ch_ctrl->tr_size > 0x7ff) {
418                 err = -E2BIG;
419                 goto out;
420         }
421         *ctrl &= ~0x7ff;
422         *ctrl |= ch_ctrl->tr_size & 0x7ff;
423
424 out:
425         return err;
426 }
427
428 EXPORT_SYMBOL_GPL(pnx4008_dma_pack_control);
429
430 int pnx4008_dma_parse_control(unsigned long ctrl,
431                               struct pnx4008_dma_ch_ctrl * ch_ctrl)
432 {
433         int err = 0;
434
435         if (!ch_ctrl) {
436                 err = -EINVAL;
437                 goto out;
438         }
439
440         ch_ctrl->tr_size = ctrl & 0x7ff;
441         ctrl >>= 12;
442
443         ch_ctrl->sbsize = 1 << (ctrl & 7);
444         if (ch_ctrl->sbsize > 1)
445                 ch_ctrl->sbsize <<= 1;
446         ctrl >>= 3;
447
448         ch_ctrl->dbsize = 1 << (ctrl & 7);
449         if (ch_ctrl->dbsize > 1)
450                 ch_ctrl->dbsize <<= 1;
451         ctrl >>= 3;
452
453         switch (ctrl & 7) {
454         case 0:
455                 ch_ctrl->swidth = WIDTH_BYTE;
456                 break;
457         case 1:
458                 ch_ctrl->swidth = WIDTH_HWORD;
459                 break;
460         case 2:
461                 ch_ctrl->swidth = WIDTH_WORD;
462                 break;
463         default:
464                 err = -EINVAL;
465                 goto out;
466         }
467         ctrl >>= 3;
468
469         switch (ctrl & 7) {
470         case 0:
471                 ch_ctrl->dwidth = WIDTH_BYTE;
472                 break;
473         case 1:
474                 ch_ctrl->dwidth = WIDTH_HWORD;
475                 break;
476         case 2:
477                 ch_ctrl->dwidth = WIDTH_WORD;
478                 break;
479         default:
480                 err = -EINVAL;
481                 goto out;
482         }
483         ctrl >>= 3;
484
485         ch_ctrl->src_ahb1 = ctrl & 1;
486         ctrl >>= 1;
487
488         ch_ctrl->dest_ahb1 = ctrl & 1;
489         ctrl >>= 1;
490
491         ch_ctrl->si = ctrl & 1;
492         ctrl >>= 1;
493
494         ch_ctrl->di = ctrl & 1;
495         ctrl >>= 1;
496
497         ch_ctrl->priv_mode = ctrl & 1;
498         ctrl >>= 1;
499
500         ch_ctrl->bufferable = ctrl & 1;
501         ctrl >>= 1;
502
503         ch_ctrl->cacheable = ctrl & 1;
504         ctrl >>= 1;
505
506         ch_ctrl->tc_mask = ctrl & 1;
507
508 out:
509         return err;
510 }
511
512 EXPORT_SYMBOL_GPL(pnx4008_dma_parse_control);
513
514 int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config * ch_cfg,
515                             unsigned long *cfg)
516 {
517         int err = 0;
518
519         if (!cfg || !ch_cfg) {
520                 err = -EINVAL;
521                 goto out;
522         }
523
524         *cfg = 0;
525
526         switch (ch_cfg->halt) {
527         case 0:
528                 break;
529         case 1:
530                 *cfg |= (1 << 18);
531                 break;
532
533         default:
534                 err = -EINVAL;
535                 goto out;
536         }
537         switch (ch_cfg->active) {
538         case 0:
539                 break;
540         case 1:
541                 *cfg |= (1 << 17);
542                 break;
543
544         default:
545                 err = -EINVAL;
546                 goto out;
547         }
548         switch (ch_cfg->lock) {
549         case 0:
550                 break;
551         case 1:
552                 *cfg |= (1 << 16);
553                 break;
554
555         default:
556                 err = -EINVAL;
557                 goto out;
558         }
559         switch (ch_cfg->itc) {
560         case 0:
561                 break;
562         case 1:
563                 *cfg |= (1 << 15);
564                 break;
565
566         default:
567                 err = -EINVAL;
568                 goto out;
569         }
570         switch (ch_cfg->ie) {
571         case 0:
572                 break;
573         case 1:
574                 *cfg |= (1 << 14);
575                 break;
576
577         default:
578                 err = -EINVAL;
579                 goto out;
580         }
581         switch (ch_cfg->flow_cntrl) {
582         case FC_MEM2MEM_DMA:
583                 *cfg &= ~(7 << 11);
584                 break;
585         case FC_MEM2PER_DMA:
586                 *cfg &= ~(7 << 11);
587                 *cfg |= (1 << 11);
588                 break;
589         case FC_PER2MEM_DMA:
590                 *cfg &= ~(7 << 11);
591                 *cfg |= (2 << 11);
592                 break;
593         case FC_PER2PER_DMA:
594                 *cfg &= ~(7 << 11);
595                 *cfg |= (3 << 11);
596                 break;
597         case FC_PER2PER_DPER:
598                 *cfg &= ~(7 << 11);
599                 *cfg |= (4 << 11);
600                 break;
601         case FC_MEM2PER_PER:
602                 *cfg &= ~(7 << 11);
603                 *cfg |= (5 << 11);
604                 break;
605         case FC_PER2MEM_PER:
606                 *cfg &= ~(7 << 11);
607                 *cfg |= (6 << 11);
608                 break;
609         case FC_PER2PER_SPER:
610                 *cfg |= (7 << 11);
611                 break;
612
613         default:
614                 err = -EINVAL;
615                 goto out;
616         }
617         *cfg &= ~(0x1f << 6);
618         *cfg |= ((ch_cfg->dest_per & 0x1f) << 6);
619
620         *cfg &= ~(0x1f << 1);
621         *cfg |= ((ch_cfg->src_per & 0x1f) << 1);
622
623 out:
624         return err;
625 }
626
627 EXPORT_SYMBOL_GPL(pnx4008_dma_pack_config);
628
629 int pnx4008_dma_parse_config(unsigned long cfg,
630                              struct pnx4008_dma_ch_config * ch_cfg)
631 {
632         int err = 0;
633
634         if (!ch_cfg) {
635                 err = -EINVAL;
636                 goto out;
637         }
638
639         cfg >>= 1;
640
641         ch_cfg->src_per = cfg & 0x1f;
642         cfg >>= 5;
643
644         ch_cfg->dest_per = cfg & 0x1f;
645         cfg >>= 5;
646
647         switch (cfg & 7) {
648         case 0:
649                 ch_cfg->flow_cntrl = FC_MEM2MEM_DMA;
650                 break;
651         case 1:
652                 ch_cfg->flow_cntrl = FC_MEM2PER_DMA;
653                 break;
654         case 2:
655                 ch_cfg->flow_cntrl = FC_PER2MEM_DMA;
656                 break;
657         case 3:
658                 ch_cfg->flow_cntrl = FC_PER2PER_DMA;
659                 break;
660         case 4:
661                 ch_cfg->flow_cntrl = FC_PER2PER_DPER;
662                 break;
663         case 5:
664                 ch_cfg->flow_cntrl = FC_MEM2PER_PER;
665                 break;
666         case 6:
667                 ch_cfg->flow_cntrl = FC_PER2MEM_PER;
668                 break;
669         case 7:
670                 ch_cfg->flow_cntrl = FC_PER2PER_SPER;
671         }
672         cfg >>= 3;
673
674         ch_cfg->ie = cfg & 1;
675         cfg >>= 1;
676
677         ch_cfg->itc = cfg & 1;
678         cfg >>= 1;
679
680         ch_cfg->lock = cfg & 1;
681         cfg >>= 1;
682
683         ch_cfg->active = cfg & 1;
684         cfg >>= 1;
685
686         ch_cfg->halt = cfg & 1;
687
688 out:
689         return err;
690 }
691
692 EXPORT_SYMBOL_GPL(pnx4008_dma_parse_config);
693
694 void pnx4008_dma_split_head_entry(struct pnx4008_dma_config * config,
695                                   struct pnx4008_dma_ch_ctrl * ctrl)
696 {
697         int new_len = ctrl->tr_size, num_entries = 0;
698         int old_len = new_len;
699         int src_width, dest_width, count = 1;
700
701         switch (ctrl->swidth) {
702         case WIDTH_BYTE:
703                 src_width = 1;
704                 break;
705         case WIDTH_HWORD:
706                 src_width = 2;
707                 break;
708         case WIDTH_WORD:
709                 src_width = 4;
710                 break;
711         default:
712                 return;
713         }
714
715         switch (ctrl->dwidth) {
716         case WIDTH_BYTE:
717                 dest_width = 1;
718                 break;
719         case WIDTH_HWORD:
720                 dest_width = 2;
721                 break;
722         case WIDTH_WORD:
723                 dest_width = 4;
724                 break;
725         default:
726                 return;
727         }
728
729         while (new_len > 0x7FF) {
730                 num_entries++;
731                 new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
732         }
733         if (num_entries != 0) {
734                 struct pnx4008_dma_ll *ll = NULL;
735                 config->ch_ctrl &= ~0x7ff;
736                 config->ch_ctrl |= new_len;
737                 if (!config->is_ll) {
738                         config->is_ll = 1;
739                         while (num_entries) {
740                                 if (!ll) {
741                                         config->ll =
742                                             pnx4008_alloc_ll_entry(&config->
743                                                                    ll_dma);
744                                         ll = config->ll;
745                                 } else {
746                                         ll->next =
747                                             pnx4008_alloc_ll_entry(&ll->
748                                                                    next_dma);
749                                         ll = ll->next;
750                                 }
751
752                                 if (ctrl->si)
753                                         ll->src_addr =
754                                             config->src_addr +
755                                             src_width * new_len * count;
756                                 else
757                                         ll->src_addr = config->src_addr;
758                                 if (ctrl->di)
759                                         ll->dest_addr =
760                                             config->dest_addr +
761                                             dest_width * new_len * count;
762                                 else
763                                         ll->dest_addr = config->dest_addr;
764                                 ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
765                                 ll->next_dma = 0;
766                                 ll->next = NULL;
767                                 num_entries--;
768                                 count++;
769                         }
770                 } else {
771                         struct pnx4008_dma_ll *ll_old = config->ll;
772                         unsigned long ll_dma_old = config->ll_dma;
773                         while (num_entries) {
774                                 if (!ll) {
775                                         config->ll =
776                                             pnx4008_alloc_ll_entry(&config->
777                                                                    ll_dma);
778                                         ll = config->ll;
779                                 } else {
780                                         ll->next =
781                                             pnx4008_alloc_ll_entry(&ll->
782                                                                    next_dma);
783                                         ll = ll->next;
784                                 }
785
786                                 if (ctrl->si)
787                                         ll->src_addr =
788                                             config->src_addr +
789                                             src_width * new_len * count;
790                                 else
791                                         ll->src_addr = config->src_addr;
792                                 if (ctrl->di)
793                                         ll->dest_addr =
794                                             config->dest_addr +
795                                             dest_width * new_len * count;
796                                 else
797                                         ll->dest_addr = config->dest_addr;
798                                 ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
799                                 ll->next_dma = 0;
800                                 ll->next = NULL;
801                                 num_entries--;
802                                 count++;
803                         }
804                         ll->next_dma = ll_dma_old;
805                         ll->next = ll_old;
806                 }
807                 /* adjust last length/tc */
808                 ll->ch_ctrl = config->ch_ctrl & (~0x7ff);
809                 ll->ch_ctrl |= old_len - new_len * (count - 1);
810                 config->ch_ctrl &= 0x7fffffff;
811         }
812 }
813
814 EXPORT_SYMBOL_GPL(pnx4008_dma_split_head_entry);
815
816 void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll * cur_ll,
817                                 struct pnx4008_dma_ch_ctrl * ctrl)
818 {
819         int new_len = ctrl->tr_size, num_entries = 0;
820         int old_len = new_len;
821         int src_width, dest_width, count = 1;
822
823         switch (ctrl->swidth) {
824         case WIDTH_BYTE:
825                 src_width = 1;
826                 break;
827         case WIDTH_HWORD:
828                 src_width = 2;
829                 break;
830         case WIDTH_WORD:
831                 src_width = 4;
832                 break;
833         default:
834                 return;
835         }
836
837         switch (ctrl->dwidth) {
838         case WIDTH_BYTE:
839                 dest_width = 1;
840                 break;
841         case WIDTH_HWORD:
842                 dest_width = 2;
843                 break;
844         case WIDTH_WORD:
845                 dest_width = 4;
846                 break;
847         default:
848                 return;
849         }
850
851         while (new_len > 0x7FF) {
852                 num_entries++;
853                 new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
854         }
855         if (num_entries != 0) {
856                 struct pnx4008_dma_ll *ll = NULL;
857                 cur_ll->ch_ctrl &= ~0x7ff;
858                 cur_ll->ch_ctrl |= new_len;
859                 if (!cur_ll->next) {
860                         while (num_entries) {
861                                 if (!ll) {
862                                         cur_ll->next =
863                                             pnx4008_alloc_ll_entry(&cur_ll->
864                                                                    next_dma);
865                                         ll = cur_ll->next;
866                                 } else {
867                                         ll->next =
868                                             pnx4008_alloc_ll_entry(&ll->
869                                                                    next_dma);
870                                         ll = ll->next;
871                                 }
872
873                                 if (ctrl->si)
874                                         ll->src_addr =
875                                             cur_ll->src_addr +
876                                             src_width * new_len * count;
877                                 else
878                                         ll->src_addr = cur_ll->src_addr;
879                                 if (ctrl->di)
880                                         ll->dest_addr =
881                                             cur_ll->dest_addr +
882                                             dest_width * new_len * count;
883                                 else
884                                         ll->dest_addr = cur_ll->dest_addr;
885                                 ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
886                                 ll->next_dma = 0;
887                                 ll->next = NULL;
888                                 num_entries--;
889                                 count++;
890                         }
891                 } else {
892                         struct pnx4008_dma_ll *ll_old = cur_ll->next;
893                         unsigned long ll_dma_old = cur_ll->next_dma;
894                         while (num_entries) {
895                                 if (!ll) {
896                                         cur_ll->next =
897                                             pnx4008_alloc_ll_entry(&cur_ll->
898                                                                    next_dma);
899                                         ll = cur_ll->next;
900                                 } else {
901                                         ll->next =
902                                             pnx4008_alloc_ll_entry(&ll->
903                                                                    next_dma);
904                                         ll = ll->next;
905                                 }
906
907                                 if (ctrl->si)
908                                         ll->src_addr =
909                                             cur_ll->src_addr +
910                                             src_width * new_len * count;
911                                 else
912                                         ll->src_addr = cur_ll->src_addr;
913                                 if (ctrl->di)
914                                         ll->dest_addr =
915                                             cur_ll->dest_addr +
916                                             dest_width * new_len * count;
917                                 else
918                                         ll->dest_addr = cur_ll->dest_addr;
919                                 ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
920                                 ll->next_dma = 0;
921                                 ll->next = NULL;
922                                 num_entries--;
923                                 count++;
924                         }
925
926                         ll->next_dma = ll_dma_old;
927                         ll->next = ll_old;
928                 }
929                 /* adjust last length/tc */
930                 ll->ch_ctrl = cur_ll->ch_ctrl & (~0x7ff);
931                 ll->ch_ctrl |= old_len - new_len * (count - 1);
932                 cur_ll->ch_ctrl &= 0x7fffffff;
933         }
934 }
935
936 EXPORT_SYMBOL_GPL(pnx4008_dma_split_ll_entry);
937
938 int pnx4008_config_channel(int ch, struct pnx4008_dma_config * config)
939 {
940         if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
941                 return -EINVAL;
942
943         pnx4008_dma_lock();
944         __raw_writel(config->src_addr, DMAC_Cx_SRC_ADDR(ch));
945         __raw_writel(config->dest_addr, DMAC_Cx_DEST_ADDR(ch));
946
947         if (config->is_ll)
948                 __raw_writel(config->ll_dma, DMAC_Cx_LLI(ch));
949         else
950                 __raw_writel(0, DMAC_Cx_LLI(ch));
951
952         __raw_writel(config->ch_ctrl, DMAC_Cx_CONTROL(ch));
953         __raw_writel(config->ch_cfg, DMAC_Cx_CONFIG(ch));
954         pnx4008_dma_unlock();
955
956         return 0;
957
958 }
959
960 EXPORT_SYMBOL_GPL(pnx4008_config_channel);
961
962 int pnx4008_channel_get_config(int ch, struct pnx4008_dma_config * config)
963 {
964         if (!VALID_CHANNEL(ch) || !dma_channels[ch].name || !config)
965                 return -EINVAL;
966
967         pnx4008_dma_lock();
968         config->ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
969         config->ch_ctrl = __raw_readl(DMAC_Cx_CONTROL(ch));
970
971         config->ll_dma = __raw_readl(DMAC_Cx_LLI(ch));
972         config->is_ll = config->ll_dma ? 1 : 0;
973
974         config->src_addr = __raw_readl(DMAC_Cx_SRC_ADDR(ch));
975         config->dest_addr = __raw_readl(DMAC_Cx_DEST_ADDR(ch));
976         pnx4008_dma_unlock();
977
978         return 0;
979 }
980
981 EXPORT_SYMBOL_GPL(pnx4008_channel_get_config);
982
983 int pnx4008_dma_ch_enable(int ch)
984 {
985         unsigned long ch_cfg;
986
987         if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
988                 return -EINVAL;
989
990         pnx4008_dma_lock();
991         ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
992         ch_cfg |= 1;
993         __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
994         pnx4008_dma_unlock();
995
996         return 0;
997 }
998
999 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enable);
1000
1001 int pnx4008_dma_ch_disable(int ch)
1002 {
1003         unsigned long ch_cfg;
1004
1005         if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
1006                 return -EINVAL;
1007
1008         pnx4008_dma_lock();
1009         ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
1010         ch_cfg &= ~1;
1011         __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
1012         pnx4008_dma_unlock();
1013
1014         return 0;
1015 }
1016
1017 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_disable);
1018
1019 int pnx4008_dma_ch_enabled(int ch)
1020 {
1021         unsigned long ch_cfg;
1022
1023         if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
1024                 return -EINVAL;
1025
1026         pnx4008_dma_lock();
1027         ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
1028         pnx4008_dma_unlock();
1029
1030         return ch_cfg & 1;
1031 }
1032
1033 EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
1034
1035 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
1036 {
1037         int i;
1038         unsigned long dint = __raw_readl(DMAC_INT_STAT);
1039         unsigned long tcint = __raw_readl(DMAC_INT_TC_STAT);
1040         unsigned long eint = __raw_readl(DMAC_INT_ERR_STAT);
1041         unsigned long i_bit;
1042
1043         for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
1044                 i_bit = 1 << i;
1045                 if (dint & i_bit) {
1046                         struct dma_channel *channel = &dma_channels[i];
1047
1048                         if (channel->name && channel->irq_handler) {
1049                                 int cause = 0;
1050
1051                                 if (eint & i_bit)
1052                                         cause |= DMA_ERR_INT;
1053                                 if (tcint & i_bit)
1054                                         cause |= DMA_TC_INT;
1055                                 channel->irq_handler(i, cause, channel->data);
1056                         } else {
1057                                 /*
1058                                  * IRQ for an unregistered DMA channel
1059                                  */
1060                                 printk(KERN_WARNING
1061                                        "spurious IRQ for DMA channel %d\n", i);
1062                         }
1063                         if (tcint & i_bit)
1064                                 __raw_writel(i_bit, DMAC_INT_TC_CLEAR);
1065                         if (eint & i_bit)
1066                                 __raw_writel(i_bit, DMAC_INT_ERR_CLEAR);
1067                 }
1068         }
1069         return IRQ_HANDLED;
1070 }
1071
1072 static int __init pnx4008_dma_init(void)
1073 {
1074         int ret, i;
1075
1076         ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
1077         if (ret) {
1078                 printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
1079                 goto out;
1080         }
1081
1082         ll_pool.count = 0x4000 / sizeof(struct pnx4008_dma_ll);
1083         ll_pool.cur = ll_pool.vaddr =
1084             dma_alloc_coherent(NULL, ll_pool.count * sizeof(struct pnx4008_dma_ll),
1085                                &ll_pool.dma_addr, GFP_KERNEL);
1086
1087         if (!ll_pool.vaddr) {
1088                 ret = -ENOMEM;
1089                 free_irq(DMA_INT, NULL);
1090                 goto out;
1091         }
1092
1093         for (i = 0; i < ll_pool.count - 1; i++) {
1094                 void **addr = ll_pool.vaddr + i * sizeof(struct pnx4008_dma_ll);
1095                 *addr = (void *)addr + sizeof(struct pnx4008_dma_ll);
1096         }
1097         *(long *)(ll_pool.vaddr +
1098                   (ll_pool.count - 1) * sizeof(struct pnx4008_dma_ll)) =
1099             (long)ll_pool.vaddr;
1100
1101         __raw_writel(1, DMAC_CONFIG);
1102
1103 out:
1104         return ret;
1105 }
1106 arch_initcall(pnx4008_dma_init);