libata: kill probe_ent and related helpers
[powerpc.git] / arch / arm / plat-s3c24xx / dma.c
index c784e1f..4540a80 100644 (file)
@@ -42,6 +42,8 @@
 static void __iomem *dma_base;
 static struct kmem_cache *dma_kmem;
 
+static int dma_channels;
+
 struct s3c24xx_dma_selection dma_sel;
 
 /* dma channel state information */
@@ -1278,7 +1280,42 @@ static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long
 
 /* initialisation code */
 
-static int __init s3c2410_init_dma(void)
+int __init s3c24xx_dma_sysclass_init(void)
+{
+       int ret = sysdev_class_register(&dma_sysclass);
+
+       if (ret != 0)
+               printk(KERN_ERR "dma sysclass registration failed\n");
+
+       return ret;
+}
+
+core_initcall(s3c24xx_dma_sysclass_init);
+
+int __init s3c24xx_dma_sysdev_register(void)
+{
+       struct s3c2410_dma_chan *cp = s3c2410_chans;
+       int channel, ret;
+
+       for (channel = 0; channel < dma_channels; cp++, channel++) {
+               cp->dev.cls = &dma_sysclass;
+               cp->dev.id  = channel;
+               ret = sysdev_register(&cp->dev);
+
+               if (ret) {
+                       printk(KERN_ERR "error registering dev for dma %d\n",
+                              channel);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+late_initcall(s3c24xx_dma_sysdev_register);
+
+int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
+                           unsigned int stride)
 {
        struct s3c2410_dma_chan *cp;
        int channel;
@@ -1286,21 +1323,16 @@ static int __init s3c2410_init_dma(void)
 
        printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
 
-       dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
+       dma_channels = channels;
+
+       dma_base = ioremap(S3C24XX_PA_DMA, stride * channels);
        if (dma_base == NULL) {
                printk(KERN_ERR "dma failed to remap register block\n");
                return -ENOMEM;
        }
 
-       printk("Registering sysclass\n");
-
-       ret = sysdev_class_register(&dma_sysclass);
-       if (ret != 0) {
-               printk(KERN_ERR "dma sysclass registration failed\n");
-               goto err;
-       }
-
-       dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0,
+       dma_kmem = kmem_cache_create("dma_desc",
+                                    sizeof(struct s3c2410_dma_buf), 0,
                                     SLAB_HWCACHE_ALIGN,
                                     s3c2410_dma_cache_ctor, NULL);
 
@@ -1310,15 +1342,15 @@ static int __init s3c2410_init_dma(void)
                goto err;
        }
 
-       for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
+       for (channel = 0; channel < channels;  channel++) {
                cp = &s3c2410_chans[channel];
 
                memset(cp, 0, sizeof(struct s3c2410_dma_chan));
 
                /* dma channel irqs are in order.. */
                cp->number = channel;
-               cp->irq    = channel + IRQ_DMA0;
-               cp->regs   = dma_base + (channel*0x40);
+               cp->irq    = channel + irq;
+               cp->regs   = dma_base + (channel * stride);
 
                /* point current stats somewhere */
                cp->stats  = &cp->stats_store;
@@ -1328,12 +1360,6 @@ static int __init s3c2410_init_dma(void)
 
                cp->load_timeout = 1<<18;
 
-               /* register system device */
-
-               cp->dev.cls = &dma_sysclass;
-               cp->dev.id  = channel;
-               ret = sysdev_register(&cp->dev);
-
                printk("DMA channel %d at %p, irq %d\n",
                       cp->number, cp->regs, cp->irq);
        }
@@ -1347,25 +1373,32 @@ static int __init s3c2410_init_dma(void)
        return ret;
 }
 
-core_initcall(s3c2410_init_dma);
+int s3c2410_dma_init(void)
+{
+       return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
+}
 
 static inline int is_channel_valid(unsigned int channel)
 {
        return (channel & DMA_CH_VALID);
 }
 
+static struct s3c24xx_dma_order *dma_order;
+
+
 /* s3c2410_dma_map_channel()
  *
  * turn the virtual channel number into a real, and un-used hardware
  * channel.
  *
- * currently this code uses first-free channel from the specified harware
- * map, not taking into account anything that the board setup code may
- * have to say about the likely peripheral set to be in use.
+ * first, try the dma ordering given to us by either the relevant
+ * dma code, or the board. Then just find the first usable free
+ * channel
 */
 
 struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
 {
+       struct s3c24xx_dma_order_ch *ord = NULL;
        struct s3c24xx_dma_map *ch_map;
        struct s3c2410_dma_chan *dmach;
        int ch;
@@ -1375,7 +1408,28 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
 
        ch_map = dma_sel.map + channel;
 
-       for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
+       /* first, try the board mapping */
+
+       if (dma_order) {
+               ord = &dma_order->channels[channel];
+
+               for (ch = 0; ch < dma_channels; ch++) {
+                       if (!is_channel_valid(ord->list[ch]))
+                               continue;
+
+                       if (s3c2410_chans[ord->list[ch]].in_use == 0) {
+                               ch = ord->list[ch] & ~DMA_CH_VALID;
+                               goto found;
+                       }
+               }
+
+               if (ord->flags & DMA_CH_NEVER)
+                       return NULL;
+       }
+
+       /* second, search the channel map for first free */
+
+       for (ch = 0; ch < dma_channels; ch++) {
                if (!is_channel_valid(ch_map->channels[ch]))
                        continue;
 
@@ -1385,11 +1439,12 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
                }
        }
 
-       if (ch >= S3C2410_DMA_CHANNELS)
+       if (ch >= dma_channels)
                return NULL;
 
        /* update our channel mapping */
 
+ found:
        dmach = &s3c2410_chans[ch];
        dma_chan_map[channel] = dmach;
 
@@ -1400,22 +1455,8 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
        return dmach;
 }
 
-static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
-{
-       /* show the channel configuration */
-
-       printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
-              (is_channel_valid(map->channels[0]) ? '0' : '-'),
-              (is_channel_valid(map->channels[1]) ? '1' : '-'),
-              (is_channel_valid(map->channels[2]) ? '2' : '-'),
-              (is_channel_valid(map->channels[3]) ? '3' : '-'));
-}
-
 static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
 {
-       if (1)
-               s3c24xx_dma_show_ch(map, ch);
-
        return 0;
 }
 
@@ -1439,3 +1480,20 @@ int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
 
        return 0;
 }
+
+int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)
+{
+       struct s3c24xx_dma_order *nord = dma_order;
+
+       if (nord == NULL)
+               nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);
+
+       if (nord == NULL) {
+               printk(KERN_ERR "no memory to store dma channel order\n");
+               return -ENOMEM;
+       }
+
+       dma_order = nord;
+       memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));
+       return 0;
+}