Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=0c6022d453ecebdace0ce15434c7108e158149ca
Commit:     0c6022d453ecebdace0ce15434c7108e158149ca
Parent:     d2a76020e3a52c6370a7d603082b4cdb3db0703e
Author:     Ben Dooks <[EMAIL PROTECTED]>
AuthorDate: Tue Feb 13 13:02:52 2007 +0100
Committer:  Russell King <[EMAIL PROTECTED]>
CommitDate: Wed Feb 14 15:04:22 2007 +0000

    [ARM] 4177/1: S3C24XX: Add DMA channel allocation order
    
    Allow the CPU code, and any board specific initialisation
    code to change the allocation order of the DMA channels,
    or stop a peripheral allocating any DMA at-all.
    
    This is due to the scarce mapping of DMA channels on
    some earlier S3C24XX cpus, where the selection changes
    depending on the channel in use.
    
    Signed-off-by: Ben Dooks <[EMAIL PROTECTED]>
    Signed-off-by: Russell King <[EMAIL PROTECTED]>
---
 Documentation/arm/Samsung-S3C24XX/DMA.txt |   46 +++++++++++++++++++++++++++
 arch/arm/plat-s3c24xx/dma.c               |   49 +++++++++++++++++++++++++++--
 include/asm-arm/plat-s3c24xx/dma.h        |   25 +++++++++++++++
 3 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/Documentation/arm/Samsung-S3C24XX/DMA.txt 
b/Documentation/arm/Samsung-S3C24XX/DMA.txt
new file mode 100644
index 0000000..37f4edc
--- /dev/null
+++ b/Documentation/arm/Samsung-S3C24XX/DMA.txt
@@ -0,0 +1,46 @@
+                       S3C2410 DMA
+                       ===========
+
+Introduction
+------------
+
+   The kernel provides an interface to manage DMA transfers
+   using the DMA channels in the cpu, so that the central
+   duty of managing channel mappings, and programming the
+   channel generators is in one place.
+
+
+DMA Channel Ordering
+--------------------
+
+   Many of the range do not have connections for the DMA
+   channels to all sources, which means that some devices
+   have a restricted number of channels that can be used.
+
+   To allow flexibilty for each cpu type and board, the
+   dma code can be given an dma ordering structure which
+   allows the order of channel search to be specified, as
+   well as allowing the prohibition of certain claims.
+
+   struct s3c24xx_dma_order has a list of channels, and
+   each channel within has a slot for a list of dma
+   channel numbers. The slots are searched in order, for
+   the presence of a dma channel number with DMA_CH_VALID
+   orred in.
+
+   If the order has the flag DMA_CH_NEVER set, then after
+   checking the channel list, the system will return no
+   found channel, thus denying the request.
+
+   A board support file can call s3c24xx_dma_order_set()
+   to register an complete ordering set. The routine will
+   copy the data, so the original can be discared with
+   __initdata.
+
+
+Authour
+-------
+
+Ben Dooks,
+Copyright (c) 2007 Ben Dooks, Simtec Electronics
+Licensed under the GPL v2
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index c784e1f..44e3943 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1354,18 +1354,22 @@ 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,6 +1379,27 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int 
channel)
 
        ch_map = dma_sel.map + channel;
 
+       /* first, try the board mapping */
+
+       if (dma_order) {
+               ord = &dma_order->channels[channel];
+
+               for (ch = 0; ch < S3C2410_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 < S3C2410_DMA_CHANNELS; ch++) {
                if (!is_channel_valid(ch_map->channels[ch]))
                        continue;
@@ -1390,6 +1415,7 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int 
channel)
 
        /* update our channel mapping */
 
+ found:
        dmach = &s3c2410_chans[ch];
        dma_chan_map[channel] = dmach;
 
@@ -1439,3 +1465,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;
+}
diff --git a/include/asm-arm/plat-s3c24xx/dma.h 
b/include/asm-arm/plat-s3c24xx/dma.h
index 421b567..15e140c 100644
--- a/include/asm-arm/plat-s3c24xx/dma.h
+++ b/include/asm-arm/plat-s3c24xx/dma.h
@@ -14,6 +14,7 @@ extern struct sysdev_class dma_sysclass;
 extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
 
 #define DMA_CH_VALID           (1<<31)
+#define DMA_CH_NEVER           (1<<30)
 
 struct s3c24xx_dma_addr {
        unsigned long           from;
@@ -43,3 +44,27 @@ struct s3c24xx_dma_selection {
 };
 
 extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+
+/* struct s3c24xx_dma_order_ch
+ *
+ * channel map for one of the `enum dma_ch` dma channels. the list
+ * entry contains a set of low-level channel numbers, orred with
+ * DMA_CH_VALID, which are checked in the order in the array.
+*/
+
+struct s3c24xx_dma_order_ch {
+       unsigned int    list[S3C2410_DMA_CHANNELS];     /* list of channels */
+       unsigned int    flags;                          /* flags */
+};
+
+/* struct s3c24xx_dma_order
+ *
+ * information provided by either the core or the board to give the
+ * dma system a hint on how to allocate channels
+*/
+
+struct s3c24xx_dma_order {
+       struct s3c24xx_dma_order_ch     channels[DMACH_MAX];
+};
+
+extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to