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