All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
@ 2009-11-26 10:42 Hu Ruihuan
  2009-11-29 12:03 ` Wan ZongShun
  2009-11-29 12:16 ` Russell King - ARM Linux
  0 siblings, 2 replies; 12+ messages in thread
From: Hu Ruihuan @ 2009-11-26 10:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Wan ZongShun
    This is the gdma driver for NUC900 platform, it is based apon the
code several days ago I have submited.

Signed-off-by: Hu Ruihuan <specter118@163.com>
----
iff -Naur linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c
linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/dma.c
--- linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c        1970-01-01
08:00:00.000000000 +0800
+++ linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/dma.c 2010-11-20
00:06:44.000000000 +0800
@@ -0,0 +1,318 @@
+/*
+ * arch/arm/mach-w90p910/dma.c
+ *
+ * Support functions for the w90p910 internal DMA channels.
+ *
+ * Wan Zongshun <mcuos.com@gmail.com>
+ * Hu Ruihuan <specter118@gmail.com>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <mach/hardware.h>
+
+#define NUC900_DMA_CHANNELS           (2)
+#define DMA_BASE                               (W90X900_VA_GDMA)
+#define GDMA_INTCS                             (DMA_BASE + 0xa0)
+
+#define GDMA_GDGA                              (0x1c)
+#define TC0F                                   (0x01 << 8)
+#define TC1F                                   (0x01 << 10)
+#define ENTC0F                                 (0x01)
+#define ENTC1F                                 (0x01 << 2)
+
+#define GDMAEN                                 (0x01)
+#define GDMAMS                                 (0x03 << 2)
+#define DADIR                                  (0x01 << 4)
+#define SADIR                                  (0x01 << 5)
+#define DAFIX                                  (0x01 << 6)
+#define SAFIX                                  (0x01 << 7)
+#define D_INTS                                 (0x01 << 10)
+#define TWSMASK                                (0x03 << 12)
+#define TWS                                    (0x02 << 12)
+
+#define RUN                                    (0x01 << 3)
+#define NON_DSCRIP                             (0x01 << 2)
+#define ORDEN                                  (0x01 << 1)
+#define RESET                                  (0x01)
+#define DSCRIPMASK                             (0x0F)
+#define CMDINFOMASK                            (0x03FFF)
+
+#define COUTN_TRANSFER                         (0x1000)/*count[13:0]=1024*/
+#define CHANNELINERV                           (0x20)
+
+typedef void (*dma_callback_t)(void *data);
+
+struct nuc900_dma_descp {
+       unsigned int next_descp;
+       unsigned int srcaddr;
+       unsigned int dstaddr;
+       unsigned int commandinfo;
+};
+
+struct nuc900_dma_t {
+       const char *device;             /* this channel device, 0  if unused */
+       dma_callback_t callback;        /* to call when DMA completes */
+       void __iomem *dma_reg;
+       void *data;                     /* ... with private data ptr */
+       struct nuc900_dma_descp *descp;
+};
+
+static struct nuc900_dma_t dma_chan[nuc900_DMA_CHANNELS];
+static struct nuc900_dma_t *dmachan0, *dmachan1;
+static atomic_t  shared_irq_using;
+static spinlock_t dma_chan_lock;
+
+
+
+static int register_dmachan_fromname(const char *dev_name,
+                       struct nuc900_dma_t *dma, unsigned int *irq_request)
+{
+       int err;
+
+       BUG_ON(!dev_name);
+
+       err = 0;
+
+       if (!(dmachan0->device) && !(dmachan1->device)) {
+               dma = dmachan0;
+               *irq_request = 1;
+       } else if ((dmachan0->device) && !(dmachan1->device)) {
+                       if (strcmp(dmachan0->device, dev_name) == 0)
+                               err = -EBUSY;
+                       else
+                               dma = dmachan1;
+       } else if ((dmachan1->device) && !(dmachan0->device)) {
+                       if (strcmp(dmachan1->device, dev_name) == 0)
+                               err = -EBUSY;
+                       else
+                               dma = dmachan0;
+       } else
+               err = -EBUSY;
+
+       return err;
+
+}
+
+static void match_dmachan_fromname(const char *dev_name,
+                                       struct nuc900_dma_t *dma)
+{
+       BUG_ON(!dev_name);
+
+       if (dmachan1->device) {
+               if (strcmp(dmachan1->device, dev_name) == 0)
+                       dma = dmachan1;
+       } else if (dmachan0->device) {
+               if (strcmp(dmachan0->device, dev_name) == 0)
+                       dma = dmachan0;
+       }
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+{
+       int status;
+       local_irq_disable();
+       status = __raw_readl(GDMA_GDGA);
+
+       if (status & (TC0F)) {
+               __raw_writel((~TC0F), GDMA_GDGA);
+               local_irq_enable();
+               dmachan0->callback(dmachan0->data);
+       }
+
+       if (status & (TC1F)) {
+               __raw_writel((~TC1F), GDMA_GDGA);
+               local_irq_enable();
+               dmachan1->callback(dmachan1->data);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
+                                                               void *data)
+{
+       struct nuc900_dma_t *dma = NULL;
+       int err, irq_request;
+
+       err = 0;
+       irq_request = 0;
+       spin_lock(&dma_chan_lock);
+       err = register_dmachan_fromname(dev_name, dma, &irq_request);
+
+       if (err < 0) {
+               spin_unlock(&dma_chan_lock);
+               return err;
+       }
+
+       dma->device = dev_name;
+
+       if (irq_request) {
+               err = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
+                               IRQF_DISABLED, NULL, NULL);
+               if (err) {
+                       dma->device = NULL;
+                       spin_unlock(&dma_chan_lock);
+                       return err;
+               }
+       }
+
+
+       atomic_inc( &shared_irq_using);
+       dma->callback = callback;
+       dma->data = data;
+       spin_unlock(&dma_chan_lock);
+       return 0;
+}
+EXPORT_SYMBOL(nuc900_request_dma);
+
+int nuc900_free_dma(const char *dev_name)
+{
+       struct nuc900_dma_t *dma = NULL;
+
+       BUG_ON(!dev_name);
+       WARN_ON(shared_irq_using.counter == 0);
+       spin_lock(&dma_chan_lock);
+       match_dmachan_fromname(dev_name, dma);
+
+       if (!dma)
+               return -ENXIO;
+
+       dma->device = NULL;
+       spin_unlock(&dma_chan_lock);
+
+       atomic_dec(&shared_irq_using);
+
+
+       if (!(shared_irq_using.counter))
+               free_irq(IRQ_GDMAGROUP, dma);
+
+       kzfree(dma->descp);
+       return 0;
+}
+EXPORT_SYMBOL(nuc900_free_dma);
+
+static unsigned int set_start_cmd(unsigned int start)
+{
+       unsigned int dscp_cmd;
+
+       dscp_cmd = 0;
+
+       if (start) {
+               dscp_cmd = (ORDEN|RUN);
+               dscp_cmd &= ~(NON_DSCRIP|RESET);
+       } else {
+               dscp_cmd = (NON_DSCRIP);
+       }
+               dscp_cmd &= DSCRIPMASK;
+
+       return dscp_cmd;
+}
+
+static unsigned int set_cmd_info(unsigned int countsize)
+{
+       unsigned int cmd_info;
+
+       cmd_info = (countsize >> 2);
+
+       cmd_info = (((cmd_info & CMDINFOMASK) << 18)|GDMAEN|D_INTS);
+       cmd_info &= ~(GDMAMS|DADIR|SADIR|DAFIX|SAFIX|TWSMASK);
+       cmd_info |= TWS;
+
+       return cmd_info;
+
+}
+
+static unsigned int get_descplist_num(unsigned int size, unsigned int *leave)
+{
+       unsigned int dscp_num, other_num;
+
+       dscp_num = 0;
+       other_num = 0;
+
+       dscp_num = size / COUTN_TRANSFER;
+       other_num = size % COUTN_TRANSFER;
+
+       if (other_num)
+               dscp_num += 1;
+
+       *leave = other_num;
+
+       return dscp_num;
+
+}
+
+int nuc900_start_dma(const char *dev_name, dma_addr_t dma_src,
+                                       dma_addr_t dma_dst, unsigned int size)
+{
+       struct nuc900_dma_descp *descp = NULL;
+       struct nuc900_dma_t *dma = NULL;
+       unsigned int i, dscp_num, other_num, val;
+
+       BUG_ON((!size|!dev_name));
+
+       match_dmachan_fromname(dev_name, dma);
+
+       if (!dma)
+               return -ENXIO;
+
+       dscp_num = get_descplist_num(size, &other_num);
+
+       descp = kzalloc(dscp_num * sizeof(struct nuc900_dma_t), GFP_KERNEL);
+
+       if (!descp)
+               return -ENOMEM;
+
+       dma->descp = descp;
+
+       for (i = 0; i < dscp_num; i++) {
+               descp->next_descp = set_start_cmd(1);
+               descp->srcaddr = dma_src + COUTN_TRANSFER * i;
+               descp->dstaddr = dma_dst + COUTN_TRANSFER * i;
+               descp->commandinfo = set_cmd_info(COUTN_TRANSFER);
+               descp++;
+       }
+       descp--;
+       descp->next_descp = set_start_cmd(0);
+       descp->commandinfo = set_cmd_info(other_num);
+
+
+       val = set_start_cmd(1);
+       val |= (unsigned int)(dma->descp);
+       local_irq_disable();
+       __raw_writel(val, dma->dma_reg + GDMA_GDGA);
+
+       val = __raw_readl(GDMA_INTCS);
+       val |= (ENTC0F|ENTC1F);
+       __raw_writel(val, GDMA_INTCS);
+       local_irq_enable();
+
+       return 0;
+}
+EXPORT_SYMBOL(nuc900_start_dma);
+
+void __init nuc900_init_dma(void)
+{
+       unsigned        i;
+       struct nuc900_dma_t *dma_channel;
+       spin_lock_init(&dma_chan_lock);
+       for (i = 0; i < NUC900_DMA_CHANNELS; i++) {
+               dma_channel = &dma_chan[i];
+               dma_channel->dma_reg = DMA_BASE + i * CHANNELINERV;
+               dma_channel->device = NULL;
+       }
+
+       dmachan0 = &dma_chan[0];
+       dmachan1 = &dma_chan[1];
+}
diff -Naur linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile
linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/Makefile
--- linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile     2009-11-20
06:32:38.000000000 +0800
+++ linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/Makefile      2010-11-20
00:02:07.000000000 +0800
@@ -5,7 +5,7 @@
 # Object file lists.

 obj-y                          := irq.o time.o mfp.o gpio.o clock.o
-obj-y                          += clksel.o dev.o cpu.o
+obj-y                          += clksel.o dev.o cpu.o dma.o
 # W90X900 CPU support files

 obj-$(CONFIG_CPU_W90P910)      += nuc910.o
----

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-11-26 10:42 [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform Hu Ruihuan
@ 2009-11-29 12:03 ` Wan ZongShun
  2009-11-29 12:16 ` Russell King - ARM Linux
  1 sibling, 0 replies; 12+ messages in thread
From: Wan ZongShun @ 2009-11-29 12:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Hu Ruihuan 

Thanks a lot for your patch, regarding this dma driver, it looks good to me,

but for submitting this patch, there are two points you should take care as following: 

(1)Please use 'scripts/checkpatch.pl' to check your patch.

(2)Before you submit some patches, Please read the Documentation/email-clients.txt
and check your email client.


> Hi, Wan ZongShun
>     This is the gdma driver for NUC900 platform, it is based apon the
> code several days ago I have submited.
> 
> Signed-off-by: Hu Ruihuan <specter118@163.com>
> ----
> iff -Naur linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c
> linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/dma.c
> --- linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c        1970-01-01
> 08:00:00.000000000 +0800
> +++ linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/dma.c 2010-11-20
> 00:06:44.000000000 +0800
> @@ -0,0 +1,318 @@
> +/*
> + * arch/arm/mach-w90p910/dma.c
> + *
> + * Support functions for the w90p910 internal DMA channels.
> + *
> + * Wan Zongshun <mcuos.com@gmail.com>
> + * Hu Ruihuan <specter118@gmail.com>
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/init.h>
> +#include <linux/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/io.h>
> +
> +#include <asm/system.h>
> +#include <asm/irq.h>
> +#include <asm/atomic.h>
> +#include <mach/hardware.h>
> +
> +#define NUC900_DMA_CHANNELS           (2)
> +#define DMA_BASE                               (W90X900_VA_GDMA)
> +#define GDMA_INTCS                             (DMA_BASE + 0xa0)
> +
> +#define GDMA_GDGA                              (0x1c)
> +#define TC0F                                   (0x01 << 8)
> +#define TC1F                                   (0x01 << 10)
> +#define ENTC0F                                 (0x01)
> +#define ENTC1F                                 (0x01 << 2)
> +
> +#define GDMAEN                                 (0x01)
> +#define GDMAMS                                 (0x03 << 2)
> +#define DADIR                                  (0x01 << 4)
> +#define SADIR                                  (0x01 << 5)
> +#define DAFIX                                  (0x01 << 6)
> +#define SAFIX                                  (0x01 << 7)
> +#define D_INTS                                 (0x01 << 10)
> +#define TWSMASK                                (0x03 << 12)
> +#define TWS                                    (0x02 << 12)
> +
> +#define RUN                                    (0x01 << 3)
> +#define NON_DSCRIP                             (0x01 << 2)
> +#define ORDEN                                  (0x01 << 1)
> +#define RESET                                  (0x01)
> +#define DSCRIPMASK                             (0x0F)
> +#define CMDINFOMASK                            (0x03FFF)
> +
> +#define COUTN_TRANSFER                         (0x1000)/*count[13:0]=1024*/
> +#define CHANNELINERV                           (0x20)
> +
> +typedef void (*dma_callback_t)(void *data);
> +
> +struct nuc900_dma_descp {
> +       unsigned int next_descp;
> +       unsigned int srcaddr;
> +       unsigned int dstaddr;
> +       unsigned int commandinfo;
> +};
> +
> +struct nuc900_dma_t {
> +       const char *device;             /* this channel device, 0  if unused */
> +       dma_callback_t callback;        /* to call when DMA completes */
> +       void __iomem *dma_reg;
> +       void *data;                     /* ... with private data ptr */
> +       struct nuc900_dma_descp *descp;
> +};
> +
> +static struct nuc900_dma_t dma_chan[nuc900_DMA_CHANNELS];
> +static struct nuc900_dma_t *dmachan0, *dmachan1;
> +static atomic_t  shared_irq_using;
> +static spinlock_t dma_chan_lock;
> +
> +
> +
> +static int register_dmachan_fromname(const char *dev_name,
> +                       struct nuc900_dma_t *dma, unsigned int *irq_request)
> +{
> +       int err;
> +
> +       BUG_ON(!dev_name);
> +
> +       err = 0;
> +
> +       if (!(dmachan0->device) && !(dmachan1->device)) {
> +               dma = dmachan0;
> +               *irq_request = 1;
> +       } else if ((dmachan0->device) && !(dmachan1->device)) {
> +                       if (strcmp(dmachan0->device, dev_name) == 0)
> +                               err = -EBUSY;
> +                       else
> +                               dma = dmachan1;
> +       } else if ((dmachan1->device) && !(dmachan0->device)) {
> +                       if (strcmp(dmachan1->device, dev_name) == 0)
> +                               err = -EBUSY;
> +                       else
> +                               dma = dmachan0;
> +       } else
> +               err = -EBUSY;
> +
> +       return err;
> +
> +}
> +
> +static void match_dmachan_fromname(const char *dev_name,
> +                                       struct nuc900_dma_t *dma)
> +{
> +       BUG_ON(!dev_name);
> +
> +       if (dmachan1->device) {
> +               if (strcmp(dmachan1->device, dev_name) == 0)
> +                       dma = dmachan1;
> +       } else if (dmachan0->device) {
> +               if (strcmp(dmachan0->device, dev_name) == 0)
> +                       dma = dmachan0;
> +       }
> +}
> +
> +static irqreturn_t dma_irq_handler(int irq, void *dev_id)
> +{
> +       int status;
> +       local_irq_disable();
> +       status = __raw_readl(GDMA_GDGA);
> +
> +       if (status & (TC0F)) {
> +               __raw_writel((~TC0F), GDMA_GDGA);
> +               local_irq_enable();
> +               dmachan0->callback(dmachan0->data);
> +       }
> +
> +       if (status & (TC1F)) {
> +               __raw_writel((~TC1F), GDMA_GDGA);
> +               local_irq_enable();
> +               dmachan1->callback(dmachan1->data);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
> +                                                               void *data)
> +{
> +       struct nuc900_dma_t *dma = NULL;
> +       int err, irq_request;
> +
> +       err = 0;
> +       irq_request = 0;
> +       spin_lock(&dma_chan_lock);
> +       err = register_dmachan_fromname(dev_name, dma, &irq_request);
> +
> +       if (err < 0) {
> +               spin_unlock(&dma_chan_lock);
> +               return err;
> +       }
> +
> +       dma->device = dev_name;
> +
> +       if (irq_request) {
> +               err = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
> +                               IRQF_DISABLED, NULL, NULL);
> +               if (err) {
> +                       dma->device = NULL;
> +                       spin_unlock(&dma_chan_lock);
> +                       return err;
> +               }
> +       }
> +
> +
> +       atomic_inc( &shared_irq_using);
> +       dma->callback = callback;
> +       dma->data = data;
> +       spin_unlock(&dma_chan_lock);
> +       return 0;
> +}
> +EXPORT_SYMBOL(nuc900_request_dma);
> +
> +int nuc900_free_dma(const char *dev_name)
> +{
> +       struct nuc900_dma_t *dma = NULL;
> +
> +       BUG_ON(!dev_name);
> +       WARN_ON(shared_irq_using.counter == 0);
> +       spin_lock(&dma_chan_lock);
> +       match_dmachan_fromname(dev_name, dma);
> +
> +       if (!dma)
> +               return -ENXIO;
> +
> +       dma->device = NULL;
> +       spin_unlock(&dma_chan_lock);
> +
> +       atomic_dec(&shared_irq_using);
> +
> +
> +       if (!(shared_irq_using.counter))
> +               free_irq(IRQ_GDMAGROUP, dma);
> +
> +       kzfree(dma->descp);
> +       return 0;
> +}
> +EXPORT_SYMBOL(nuc900_free_dma);
> +
> +static unsigned int set_start_cmd(unsigned int start)
> +{
> +       unsigned int dscp_cmd;
> +
> +       dscp_cmd = 0;
> +
> +       if (start) {
> +               dscp_cmd = (ORDEN|RUN);
> +               dscp_cmd &= ~(NON_DSCRIP|RESET);
> +       } else {
> +               dscp_cmd = (NON_DSCRIP);
> +       }
> +               dscp_cmd &= DSCRIPMASK;
> +
> +       return dscp_cmd;
> +}
> +
> +static unsigned int set_cmd_info(unsigned int countsize)
> +{
> +       unsigned int cmd_info;
> +
> +       cmd_info = (countsize >> 2);
> +
> +       cmd_info = (((cmd_info & CMDINFOMASK) << 18)|GDMAEN|D_INTS);
> +       cmd_info &= ~(GDMAMS|DADIR|SADIR|DAFIX|SAFIX|TWSMASK);
> +       cmd_info |= TWS;
> +
> +       return cmd_info;
> +
> +}
> +
> +static unsigned int get_descplist_num(unsigned int size, unsigned int *leave)
> +{
> +       unsigned int dscp_num, other_num;
> +
> +       dscp_num = 0;
> +       other_num = 0;
> +
> +       dscp_num = size / COUTN_TRANSFER;
> +       other_num = size % COUTN_TRANSFER;
> +
> +       if (other_num)
> +               dscp_num += 1;
> +
> +       *leave = other_num;
> +
> +       return dscp_num;
> +
> +}
> +
> +int nuc900_start_dma(const char *dev_name, dma_addr_t dma_src,
> +                                       dma_addr_t dma_dst, unsigned int size)
> +{
> +       struct nuc900_dma_descp *descp = NULL;
> +       struct nuc900_dma_t *dma = NULL;
> +       unsigned int i, dscp_num, other_num, val;
> +
> +       BUG_ON((!size|!dev_name));
> +
> +       match_dmachan_fromname(dev_name, dma);
> +
> +       if (!dma)
> +               return -ENXIO;
> +
> +       dscp_num = get_descplist_num(size, &other_num);
> +
> +       descp = kzalloc(dscp_num * sizeof(struct nuc900_dma_t), GFP_KERNEL);
> +
> +       if (!descp)
> +               return -ENOMEM;
> +
> +       dma->descp = descp;
> +
> +       for (i = 0; i < dscp_num; i++) {
> +               descp->next_descp = set_start_cmd(1);
> +               descp->srcaddr = dma_src + COUTN_TRANSFER * i;
> +               descp->dstaddr = dma_dst + COUTN_TRANSFER * i;
> +               descp->commandinfo = set_cmd_info(COUTN_TRANSFER);
> +               descp++;
> +       }
> +       descp--;
> +       descp->next_descp = set_start_cmd(0);
> +       descp->commandinfo = set_cmd_info(other_num);
> +
> +
> +       val = set_start_cmd(1);
> +       val |= (unsigned int)(dma->descp);
> +       local_irq_disable();
> +       __raw_writel(val, dma->dma_reg + GDMA_GDGA);
> +
> +       val = __raw_readl(GDMA_INTCS);
> +       val |= (ENTC0F|ENTC1F);
> +       __raw_writel(val, GDMA_INTCS);
> +       local_irq_enable();
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(nuc900_start_dma);
> +
> +void __init nuc900_init_dma(void)
> +{
> +       unsigned        i;
> +       struct nuc900_dma_t *dma_channel;
> +       spin_lock_init(&dma_chan_lock);
> +       for (i = 0; i < NUC900_DMA_CHANNELS; i++) {
> +               dma_channel = &dma_chan[i];
> +               dma_channel->dma_reg = DMA_BASE + i * CHANNELINERV;
> +               dma_channel->device = NULL;
> +       }
> +
> +       dmachan0 = &dma_chan[0];
> +       dmachan1 = &dma_chan[1];
> +}
> diff -Naur linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile
> linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/Makefile
> --- linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile     2009-11-20
> 06:32:38.000000000 +0800
> +++ linux-2.6.32-rc8-modify/arch/arm/mach-w90x900/Makefile      2010-11-20
> 00:02:07.000000000 +0800
> @@ -5,7 +5,7 @@
>  # Object file lists.
> 
>  obj-y                          := irq.o time.o mfp.o gpio.o clock.o
> -obj-y                          += clksel.o dev.o cpu.o
> +obj-y                          += clksel.o dev.o cpu.o dma.o
>  # W90X900 CPU support files
> 
>  obj-$(CONFIG_CPU_W90P910)      += nuc910.o
> ----
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-11-26 10:42 [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform Hu Ruihuan
  2009-11-29 12:03 ` Wan ZongShun
@ 2009-11-29 12:16 ` Russell King - ARM Linux
  2009-12-07 15:53   ` Hu Ruihuan
  1 sibling, 1 reply; 12+ messages in thread
From: Russell King - ARM Linux @ 2009-11-29 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

Some comments below.

On Thu, Nov 26, 2009 at 06:42:12PM +0800, Hu Ruihuan wrote:
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/init.h>
> +#include <linux/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/io.h>
> +
> +#include <asm/system.h>

You shouldn't need asm/system.h

> +#include <asm/irq.h>
> +#include <asm/atomic.h>
> +#include <mach/hardware.h>
> +
> +#define NUC900_DMA_CHANNELS           (2)
> +#define DMA_BASE                               (W90X900_VA_GDMA)
> +#define GDMA_INTCS                             (DMA_BASE + 0xa0)
> +
> +#define GDMA_GDGA                              (0x1c)
> +#define TC0F                                   (0x01 << 8)
> +#define TC1F                                   (0x01 << 10)
> +#define ENTC0F                                 (0x01)
> +#define ENTC1F                                 (0x01 << 2)
> +
> +#define GDMAEN                                 (0x01)
> +#define GDMAMS                                 (0x03 << 2)
> +#define DADIR                                  (0x01 << 4)
> +#define SADIR                                  (0x01 << 5)
> +#define DAFIX                                  (0x01 << 6)
> +#define SAFIX                                  (0x01 << 7)
> +#define D_INTS                                 (0x01 << 10)
> +#define TWSMASK                                (0x03 << 12)
> +#define TWS                                    (0x02 << 12)
> +
> +#define RUN                                    (0x01 << 3)
> +#define NON_DSCRIP                             (0x01 << 2)
> +#define ORDEN                                  (0x01 << 1)
> +#define RESET                                  (0x01)
> +#define DSCRIPMASK                             (0x0F)
> +#define CMDINFOMASK                            (0x03FFF)
> +
> +#define COUTN_TRANSFER                         (0x1000)/*count[13:0]=1024*/
> +#define CHANNELINERV                           (0x20)
> +
> +typedef void (*dma_callback_t)(void *data);
> +
> +struct nuc900_dma_descp {
> +       unsigned int next_descp;
> +       unsigned int srcaddr;
> +       unsigned int dstaddr;
> +       unsigned int commandinfo;
> +};
> +
> +struct nuc900_dma_t {
> +       const char *device;             /* this channel device, 0  if unused */
> +       dma_callback_t callback;        /* to call when DMA completes */
> +       void __iomem *dma_reg;
> +       void *data;                     /* ... with private data ptr */
> +       struct nuc900_dma_descp *descp;
> +};
> +
> +static struct nuc900_dma_t dma_chan[nuc900_DMA_CHANNELS];
> +static struct nuc900_dma_t *dmachan0, *dmachan1;
> +static atomic_t  shared_irq_using;
> +static spinlock_t dma_chan_lock;

Maybe consider using DEFINE_SPINLOCK(dma_chan_lock) ?

> +
> +
> +
> +static int register_dmachan_fromname(const char *dev_name,
> +                       struct nuc900_dma_t *dma, unsigned int *irq_request)
> +{
> +       int err;
> +
> +       BUG_ON(!dev_name);
> +
> +       err = 0;
> +
> +       if (!(dmachan0->device) && !(dmachan1->device)) {
> +               dma = dmachan0;
> +               *irq_request = 1;
> +       } else if ((dmachan0->device) && !(dmachan1->device)) {
> +                       if (strcmp(dmachan0->device, dev_name) == 0)
> +                               err = -EBUSY;
> +                       else
> +                               dma = dmachan1;
> +       } else if ((dmachan1->device) && !(dmachan0->device)) {
> +                       if (strcmp(dmachan1->device, dev_name) == 0)
> +                               err = -EBUSY;
> +                       else
> +                               dma = dmachan0;
> +       } else
> +               err = -EBUSY;
> +
> +       return err;
> +
> +}

Again, this initializes the local 'dma' pointer but doesn't return it.
If you want to be able to return a pointer as well as an error code,
try using linux/err.h:

struct nuc900_dma_t *register_dma_from_chan(const char *dev_name,
		unsigned int *irq_request)
{
	struct nuc900_dma_t *ret;
	...
		if (strcmp(dmachanX->device, dev_name) == 0)
			ret = ERR_PTR(-EBUSY);
		else
			ret = dmachan1;
	...
	return ret;
}

and use it as:

	struct nuc900_dma_t *dma;

	dma = register_dma_from_chan(...);
	if (IS_ERR(dma)) {
		err = PTR_ERR(dma);
		return err;
	}

This has advantages over the 'return via pointer-to-pointer in function
arguments' in that you can't end up with errors where your pointer is
not initialized.

> +
> +static void match_dmachan_fromname(const char *dev_name,
> +                                       struct nuc900_dma_t *dma)
> +{
> +       BUG_ON(!dev_name);
> +
> +       if (dmachan1->device) {
> +               if (strcmp(dmachan1->device, dev_name) == 0)
> +                       dma = dmachan1;
> +       } else if (dmachan0->device) {
> +               if (strcmp(dmachan0->device, dev_name) == 0)
> +                       dma = dmachan0;
> +       }

This code doesn't actually do anything - 'dma' is a local pointer which
you're initializing but not using.

> +}
> +
> +static irqreturn_t dma_irq_handler(int irq, void *dev_id)
> +{
> +       int status;
> +       local_irq_disable();
> +       status = __raw_readl(GDMA_GDGA);
> +
> +       if (status & (TC0F)) {
> +               __raw_writel((~TC0F), GDMA_GDGA);
> +               local_irq_enable();
> +               dmachan0->callback(dmachan0->data);
> +       }
> +
> +       if (status & (TC1F)) {
> +               __raw_writel((~TC1F), GDMA_GDGA);
> +               local_irq_enable();
> +               dmachan1->callback(dmachan1->data);
> +       }

if both TC0F and TC1F are both set, you'll write ~TC0F with IRQs disabled
but ~TC1F with IRQs enabled.  Wouldn't something like:

	local_irq_disable();
	status = __raw_readl(GDMA_GDGA) & (TC0F|TC1F);
	__raw_writel(~status, GDMA_GDGA);
	local_irq_enable();

	if (status & TC0F)
		dmachan0->callback(dmachan0->data);
	if (status & TC1F)
		dmachan1->callback(dmachan1->data);

be better?

> +
> +       return IRQ_HANDLED;
> +}
> +
> +int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
> +                                                               void *data)
> +{
> +       struct nuc900_dma_t *dma = NULL;
> +       int err, irq_request;
> +
> +       err = 0;
> +       irq_request = 0;
> +       spin_lock(&dma_chan_lock);
> +       err = register_dmachan_fromname(dev_name, dma, &irq_request);
> +
> +       if (err < 0) {
> +               spin_unlock(&dma_chan_lock);
> +               return err;
> +       }
> +
> +       dma->device = dev_name;
> +
> +       if (irq_request) {
> +               err = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
> +                               IRQF_DISABLED, NULL, NULL);

Not sure why you don't claim this at initialization time.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-11-29 12:16 ` Russell King - ARM Linux
@ 2009-12-07 15:53   ` Hu Ruihuan
  2009-12-07 17:18     ` Russell King - ARM Linux
  0 siblings, 1 reply; 12+ messages in thread
From: Hu Ruihuan @ 2009-12-07 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,Russell
  Thank you for your advice, it's my patch below follow your advice.

Signed-off-by: Hu Ruihuan<specter118@gmail.com>
---
diff -uNr a/arch/arm/mach-w90x900/dma.c
b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c
--- a/arch/arm/mach-w90x900/dma.c	2009-12-06 11:30:27.000000000 +0800
+++ b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c	1970-01-01
08:00:00.000000000 +0800
@@ -1,298 +0,0 @@
-/*
- * arch/arm/mach-w90p910/dma.c
- *
- * Support functions for the w90p910 internal DMA channels.
- *
- * Wan Zongshun <mcuos.com@gmail.com>
- * Hu Ruihuan <specter118@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/atomic.h>
-#include <mach/hardware.h>
-
-#define NUC900_DMA_CHANNELS		(2)
-#define DMA_BASE 						(W90X900_VA_GDMA)
-#define GDMA_INTCS					(DMA_BASE + 0xa0)
-
-#define GDMA_GDGA					(0x1c)
-#define TC0F							(0x01 << 8)
-#define TC1F							(0x01 << 10)
-#define ENTC0F							(0x01)
-#define ENTC1F							(0x01 << 2)
-
-#define GDMAEN						(0x01)
-#define GDMAMS						(0x03 << 2)
-#define DADIR							(0x01 << 4)
-#define SADIR							(0x01 << 5)
-#define DAFIX							(0x01 << 6)
-#define SAFIX							(0x01 << 7)
-#define D_INTS							(0x01 << 10)
-#define TWSMASK						(0x03 << 12)
-#define TWS							(0x02 << 12)
-
-#define RUN								(0x01 << 3)
-#define NON_DSCRIP					(0x01 << 2)
-#define ORDEN							(0x01 << 1)
-#define RESET							(0x01)
-#define DSCRIPMASK					(0x0F)
-#define CMDINFOMASK					(0x03FFF)
-
-#define COUTN_TRANSFER				(0x1000)/*count[13:0]=1024*/
-#define CHANNELINERV					(0x20)
-
-typedef void (*dma_callback_t)(void *data);
-
-struct nuc900_dma_descp {
-	unsigned int next_descp;
-	unsigned int srcaddr;
-	unsigned int dstaddr;
-	unsigned int commandinfo;
-};
-
-typedef struct nuc900_dma {
-	const char *device;		/* this channel device, 0  if unused */
-	dma_callback_t callback;	/* to call when DMA completes */
-	void __iomem *dma_reg;
-	void *data;			/* ... with private data ptr */
-	struct nuc900_dma_descp *descp;
-} *nuc900_dma_t;
-
-static struct nuc900_dma  dma_chan[NUC900_DMA_CHANNELS];
-static struct nuc900_dma *dmachan0, *dmachan1;
-static atomic_t  shared_irq_using;
-static DEFINE_SPINLOCK(dma_chan_lock);
-static nuc900_dma_t  register_dmachan_fromname(const char *dev_name,
-				unsigned int *irq_request)
-{
-	nuc900_dma_t ret = NULL;
-
-	BUG_ON(!dev_name);
-
-
-	if (!(dmachan0->device) && !(dmachan1->device)) {
-		ret = dmachan0;
-		*irq_request = 1;
-	} else if ((dmachan0->device) && !(dmachan1->device)) {
-			if (strcmp(dmachan0->device, dev_name) == 0)
-				ret = ERR_PTR(-EBUSY);
-			else
-				ret = dmachan1;
-	} else if ((dmachan1->device) && !(dmachan0->device)) {
-			if (strcmp(dmachan1->device, dev_name) == 0)
-				ret = ERR_PTR(-EBUSY);
-			else
-				ret = dmachan0;
-	} else
-		ret = ERR_PTR(-EBUSY);
-
-	return ret;
-
-}
-
-static void match_dmachan_fromname(const char *dev_name,
-					struct nuc900_dma  **dma)
-{
-	BUG_ON(!dev_name);
-
-	if (dmachan1->device) {
-		if (strcmp(dmachan1->device, dev_name) == 0)
-			*dma = dmachan1;
-	} else if (dmachan0->device) {
-		if (strcmp(dmachan0->device, dev_name) == 0)
-			*dma = dmachan0;
-	}
-}
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-	int status;
-      local_irq_disable();
-	status = __raw_readl(GDMA_GDGA) & (TC0F|TC1F);
-	__raw_writel(~status, GDMA_GDGA);
-	local_irq_enable();
-
-      if (status & TC0F)
-              dmachan0->callback(dmachan0->data);
-      if (status & TC1F)
-              dmachan1->callback(dmachan1->data);
-
-
-	return IRQ_HANDLED;
-}
-
-int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
-								void *data)
-{
-	struct nuc900_dma  *dma = NULL;
-	int err, irq_request;
-	err = 0;
-	irq_request = 0;
-	spin_lock(&dma_chan_lock);
-	dma = register_dmachan_fromname(dev_name, &irq_request);
-
-	if (IS_ERR(dma)) {
-		err = ERR_PTR(dma);
-		spin_unlock(&dma_chan_lock);
-		return err;
-	}
-	dma->device = dev_name;
-	
-	atomic_inc( &shared_irq_using);
-	dma->callback = callback;
-	dma->data = data;
-	spin_unlock(&dma_chan_lock);
-	return 0;
-}
-EXPORT_SYMBOL(nuc900_request_dma);
-
-int nuc900_free_dma(const char *dev_name)
-{
-	struct nuc900_dma  *dma = NULL;
-
-	BUG_ON(!dev_name);
-	WARN_ON(shared_irq_using.counter == 0);
-      spin_lock(&dma_chan_lock);
-	match_dmachan_fromname(dev_name, &dma);
-
-	if (!dma)
-		return -ENXIO;
-
-	dma->device = NULL;
-	spin_unlock(&dma_chan_lock);
-
-	atomic_dec(&shared_irq_using);
-
-	kzfree(dma->descp);
-	return 0;
-}
-EXPORT_SYMBOL(nuc900_free_dma);
-
-static unsigned int set_start_cmd(unsigned int start)
-{
-	unsigned int dscp_cmd;
-
-	dscp_cmd = 0;
-
-	if (start) {
-		dscp_cmd = (ORDEN|RUN);
-		dscp_cmd &= ~(NON_DSCRIP|RESET);
-	} else {
-		dscp_cmd = (NON_DSCRIP);
-	}
-		dscp_cmd &= DSCRIPMASK;
-
-	return dscp_cmd;
-}
-
-static unsigned int set_cmd_info(unsigned int countsize)
-{
-	unsigned int cmd_info;
-
-	cmd_info = (countsize >> 2);
-
-	cmd_info = (((cmd_info & CMDINFOMASK) << 18)|GDMAEN|D_INTS);
-	cmd_info &= ~(GDMAMS|DADIR|SADIR|DAFIX|SAFIX|TWSMASK);
-	cmd_info |= TWS;
-
-	return cmd_info;
-
-}
-
-static unsigned int get_descplist_num(unsigned int size, unsigned int *leave)
-{
-	unsigned int dscp_num, other_num;
-
-	dscp_num = 0;
-	other_num = 0;
-
-	dscp_num = size / COUTN_TRANSFER;
-	other_num = size % COUTN_TRANSFER;
-
-	if (other_num)
-		dscp_num += 1;
-
-	*leave = other_num;
-
-	return dscp_num;
-
-}
-
-int nuc900_start_dma(const char *dev_name, dma_addr_t dma_src,
-					dma_addr_t dma_dst, unsigned int size)
-{
-	struct nuc900_dma_descp *descp = NULL;
-	struct nuc900_dma  *dma = NULL;
-	unsigned int i, dscp_num, other_num, val;
-
-	BUG_ON((!size|!dev_name));
-
-	match_dmachan_fromname(dev_name, &dma);
-
-	if (!dma)
-		return -ENXIO;
-
-	dscp_num = get_descplist_num(size, &other_num);
-
-	descp = kzalloc(dscp_num * sizeof(struct nuc900_dma), GFP_KERNEL);
-
-	if (!descp)
-		return -ENOMEM;
-
-	dma->descp = descp;
-
-	for (i = 0; i < dscp_num; i++) {
-		descp->next_descp = set_start_cmd(1);
-		descp->srcaddr = dma_src + COUTN_TRANSFER * i;
-		descp->dstaddr = dma_dst + COUTN_TRANSFER * i;
-		descp->commandinfo = set_cmd_info(COUTN_TRANSFER);
-		descp++;
-	}
-	descp--;
-	descp->next_descp = set_start_cmd(0);
-	descp->commandinfo = set_cmd_info(other_num);
-
-
-	val = set_start_cmd(1);
-	val |= (unsigned int)(dma->descp);
-	local_irq_disable();
-	__raw_writel(val, dma->dma_reg + GDMA_GDGA);
-
-	val = __raw_readl(GDMA_INTCS);
-	val |= (ENTC0F|ENTC1F);
-	__raw_writel(val, GDMA_INTCS);
-	local_irq_enable();
-
-	return 0;
-}
-EXPORT_SYMBOL(nuc900_start_dma);
-
-void __init nuc900_init_dma(void)
-{
-	unsigned	i, ret;
-	struct nuc900_dma  *dma_channel;
-	spin_lock_init(&dma_chan_lock);
-	for (i = 0; i < NUC900_DMA_CHANNELS; i++) {
-		dma_channel = &dma_chan[i];
-		dma_channel->dma_reg = DMA_BASE + i * CHANNELINERV;
-		dma_channel->device = NULL;
-	}
-	ret = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
-			IRQF_DISABLED, NULL, NULL);
-	if (ret)
-		printk("unable to register nuc900 dma interrupt: %d\n", ret);
-	dmachan0 = &dma_chan[0];
-	dmachan1 = &dma_chan[1];
-}
diff -uNr a/arch/arm/mach-w90x900/Makefile
b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile
--- a/arch/arm/mach-w90x900/Makefile	2009-12-06 12:34:47.000000000 +0800
+++ b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile	2009-11-20
06:32:38.000000000 +0800
@@ -5,7 +5,7 @@
 # Object file lists.

 obj-y				:= irq.o time.o mfp.o gpio.o clock.o
-obj-y				+= clksel.o dev.o cpu.o dma.o
+obj-y				+= clksel.o dev.o cpu.o
 # W90X900 CPU support files

 obj-$(CONFIG_CPU_W90P910)	+= nuc910.o

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-07 15:53   ` Hu Ruihuan
@ 2009-12-07 17:18     ` Russell King - ARM Linux
  2009-12-07 18:11       ` Hu Ruihuan
  0 siblings, 1 reply; 12+ messages in thread
From: Russell King - ARM Linux @ 2009-12-07 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 07, 2009 at 11:53:39PM +0800, Hu Ruihuan wrote:
> Hi,Russell
>   Thank you for your advice, it's my patch below follow your advice.

Did you look at the patch before you sent it?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-07 17:18     ` Russell King - ARM Linux
@ 2009-12-07 18:11       ` Hu Ruihuan
  2009-12-07 18:39         ` Russell King - ARM Linux
  2009-12-08  3:03         ` Wan ZongShun
  0 siblings, 2 replies; 12+ messages in thread
From: Hu Ruihuan @ 2009-12-07 18:11 UTC (permalink / raw)
  To: linux-arm-kernel

yes,why?

2009/12/8 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Mon, Dec 07, 2009 at 11:53:39PM +0800, Hu Ruihuan wrote:
>> Hi,Russell
>> ? Thank you for your advice, it's my patch below follow your advice.
>
> Did you look at the patch before you sent it?
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-07 18:11       ` Hu Ruihuan
@ 2009-12-07 18:39         ` Russell King - ARM Linux
  2009-12-08  3:03         ` Wan ZongShun
  1 sibling, 0 replies; 12+ messages in thread
From: Russell King - ARM Linux @ 2009-12-07 18:39 UTC (permalink / raw)
  To: linux-arm-kernel

.yleritne selif eht gniteled eb ot sraeppa tI

On Tue, Dec 08, 2009 at 02:11:38AM +0800, Hu Ruihuan wrote:
> yes,why?
> 
> 2009/12/8 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> > On Mon, Dec 07, 2009 at 11:53:39PM +0800, Hu Ruihuan wrote:
> >> Hi,Russell
> >> ? Thank you for your advice, it's my patch below follow your advice.
> >
> > Did you look at the patch before you sent it?
> >

(My reply is backwards because you've top-posted.  Please don't do that.)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-07 18:11       ` Hu Ruihuan
  2009-12-07 18:39         ` Russell King - ARM Linux
@ 2009-12-08  3:03         ` Wan ZongShun
  2009-12-08 15:47           ` Hu Ruihuan
  1 sibling, 1 reply; 12+ messages in thread
From: Wan ZongShun @ 2009-12-08  3:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi  Hu,

When you make your patch via 'diff -uNr a b xx.patch', Please do pay
attention to the order of a and b.

I think you would want to add the DMA driver rather than delete this,
notice your all  '-'  symbol of this patch.

2009/12/8 Hu Ruihuan <specter118@gmail.com>:
> yes,why?
>
> 2009/12/8 Russell King - ARM Linux <linux@arm.linux.org.uk>:
>> On Mon, Dec 07, 2009 at 11:53:39PM +0800, Hu Ruihuan wrote:
>>> Hi,Russell
>>> ? Thank you for your advice, it's my patch below follow your advice.
>>
>> Did you look at the patch before you sent it?
>>
>



-- 
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-08  3:03         ` Wan ZongShun
@ 2009-12-08 15:47           ` Hu Ruihuan
  2009-12-09 14:50             ` Wan ZongShun
  0 siblings, 1 reply; 12+ messages in thread
From: Hu Ruihuan @ 2009-12-08 15:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Wan,
  I am sorry to make such a stupid mistake. The correct patch below.

Signed-off-by: Hu Ruihuan <specter118@gmail.com>
---
diff -uNr b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c
a/arch/arm/mach-w90x900/dma.c
--- b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c	1970-01-01
08:00:00.000000000 +0800
+++ a/arch/arm/mach-w90x900/dma.c	2009-12-08 23:34:39.000000000 +0800
@@ -0,0 +1,295 @@
+/*
+ * arch/arm/mach-w90p910/dma.c
+ *
+ * Support functions for the w90p910 internal DMA channels.
+ *
+ * Wan Zongshun <mcuos.com@gmail.com>
+ * Hu Ruihuan <specter118@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <mach/hardware.h>
+
+#define NUC900_DMA_CHANNELS			(2)
+#define DMA_BASE 				(W90X900_VA_GDMA)
+#define GDMA_INTCS				(DMA_BASE + 0xa0)
+#define GDMA_GDGA				(0x1c)
+#define TC0F					(0x01 << 8)
+#define TC1F					(0x01 << 10)
+#define ENTC0F					(0x01)
+#define ENTC1F					(0x01 << 2)
+
+#define GDMAEN				        (0x01)
+#define GDMAMS					(0x03 << 2)
+#define DADIR					(0x01 << 4)
+#define SADIR					(0x01 << 5)
+#define DAFIX					(0x01 << 6)
+#define SAFIX					(0x01 << 7)
+#define D_INTS					(0x01 << 10)
+#define TWSMASK					(0x03 << 12)
+#define TWS					(0x02 << 12)
+
+#define RUN				        (0x01 << 3)
+#define NON_DSCRIP				(0x01 << 2)
+#define ORDEN					(0x01 << 1)
+#define RESET					(0x01)
+#define DSCRIPMASK			        (0x0F)
+#define CMDINFOMASK				(0x03FFF)
+
+#define COUTN_TRANSFER				(0x1000)/*count[13:0]=1024*/
+#define CHANNELINERV				(0x20)
+
+typedef void (*dma_callback_t)(void *data);
+
+struct nuc900_dma_descp {
+	unsigned int next_descp;
+	unsigned int srcaddr;
+	unsigned int dstaddr;
+	unsigned int commandinfo;
+};
+
+struct nuc900_dma {
+	const char *device;		/* this channel device, 0  if unused */
+	dma_callback_t callback;	/* to call when DMA completes */
+	void __iomem *dma_reg;
+	void *data;			/* ... with private data ptr */
+	struct nuc900_dma_descp *descp;
+};
+
+static struct nuc900_dma  dma_chan[NUC900_DMA_CHANNELS];
+static struct nuc900_dma *dmachan0, *dmachan1;
+static atomic_t  shared_irq_using;
+static DEFINE_SPINLOCK(dma_chan_lock);
+static struct nuc900_dma *register_dmachan_fromname(const char *dev_name,
+			unsigned int *irq_request)
+{
+	struct nuc900_dma *ret = NULL;
+
+	BUG_ON(!dev_name);
+
+
+	if (!(dmachan0->device) && !(dmachan1->device)) {
+		ret = dmachan0;
+		*irq_request = 1;
+	} else if ((dmachan0->device) && !(dmachan1->device)) {
+			if (strcmp(dmachan0->device, dev_name) == 0)
+				ret = ERR_PTR(-EBUSY);
+			else
+				ret = dmachan1;
+	} else if ((dmachan1->device) && !(dmachan0->device)) {
+			if (strcmp(dmachan1->device, dev_name) == 0)
+				ret = ERR_PTR(-EBUSY);
+			else
+				ret = dmachan0;
+	} else
+		ret = ERR_PTR(-EBUSY);
+
+	return ret;
+
+}
+
+static void match_dmachan_fromname(const char *dev_name,
+					struct nuc900_dma  **dma)
+{
+	BUG_ON(!dev_name);
+
+	if (dmachan1->device) {
+		if (strcmp(dmachan1->device, dev_name) == 0)
+			*dma = dmachan1;
+	} else if (dmachan0->device) {
+		if (strcmp(dmachan0->device, dev_name) == 0)
+			*dma = dmachan0;
+	}
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+{
+	int status;
+	local_irq_disable();
+	status = __raw_readl(GDMA_GDGA) & (TC0F|TC1F);
+	__raw_writel(~status, GDMA_GDGA);
+	local_irq_enable();
+
+	if (status & TC0F)
+		dmachan0->callback(dmachan0->data);
+	if (status & TC1F)
+		dmachan1->callback(dmachan1->data);
+
+	return IRQ_HANDLED;
+}
+
+int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
+								void *data)
+{
+	struct nuc900_dma  *dma = NULL;
+	int err, irq_request;
+	err = 0;
+	irq_request = 0;
+	spin_lock(&dma_chan_lock);
+	dma = register_dmachan_fromname(dev_name, &irq_request);
+
+	if (IS_ERR(dma)) {
+		err = ERR_PTR(dma);
+		spin_unlock(&dma_chan_lock);
+		return err;
+	}
+	dma->device = dev_name;
+	atomic_inc(&shared_irq_using);
+	dma->callback = callback;
+	dma->data = data;
+	spin_unlock(&dma_chan_lock);
+	return 0;
+}
+EXPORT_SYMBOL(nuc900_request_dma);
+
+int nuc900_free_dma(const char *dev_name)
+{
+	struct nuc900_dma  *dma = NULL;
+
+	BUG_ON(!dev_name);
+	WARN_ON(shared_irq_using.counter == 0);
+	spin_lock(&dma_chan_lock);
+	match_dmachan_fromname(dev_name, &dma);
+
+	if (!dma)
+		return -ENXIO;
+
+	dma->device = NULL;
+	spin_unlock(&dma_chan_lock);
+
+	atomic_dec(&shared_irq_using);
+
+	kzfree(dma->descp);
+	return 0;
+}
+EXPORT_SYMBOL(nuc900_free_dma);
+
+static unsigned int set_start_cmd(unsigned int start)
+{
+	unsigned int dscp_cmd;
+
+	dscp_cmd = 0;
+
+	if (start) {
+		dscp_cmd = (ORDEN|RUN);
+		dscp_cmd &= ~(NON_DSCRIP|RESET);
+	} else {
+		dscp_cmd = (NON_DSCRIP);
+	}
+		dscp_cmd &= DSCRIPMASK;
+
+	return dscp_cmd;
+}
+
+static unsigned int set_cmd_info(unsigned int countsize)
+{
+	unsigned int cmd_info;
+
+	cmd_info = (countsize >> 2);
+
+	cmd_info = (((cmd_info & CMDINFOMASK) << 18)|GDMAEN|D_INTS);
+	cmd_info &= ~(GDMAMS|DADIR|SADIR|DAFIX|SAFIX|TWSMASK);
+	cmd_info |= TWS;
+
+	return cmd_info;
+
+}
+
+static unsigned int get_descplist_num(unsigned int size, unsigned int *leave)
+{
+	unsigned int dscp_num, other_num;
+
+	dscp_num = 0;
+	other_num = 0;
+
+	dscp_num = size / COUTN_TRANSFER;
+	other_num = size % COUTN_TRANSFER;
+
+	if (other_num)
+		dscp_num += 1;
+
+	*leave = other_num;
+
+	return dscp_num;
+
+}
+
+int nuc900_start_dma(const char *dev_name, dma_addr_t dma_src,
+					dma_addr_t dma_dst, unsigned int size)
+{
+	struct nuc900_dma_descp *descp = NULL;
+	struct nuc900_dma  *dma = NULL;
+	unsigned int i, dscp_num, other_num, val;
+
+	BUG_ON((!size|!dev_name));
+
+	match_dmachan_fromname(dev_name, &dma);
+
+	if (!dma)
+		return -ENXIO;
+
+	dscp_num = get_descplist_num(size, &other_num);
+
+	descp = kzalloc(dscp_num * sizeof(struct nuc900_dma), GFP_KERNEL);
+
+	if (!descp)
+		return -ENOMEM;
+
+	dma->descp = descp;
+
+	for (i = 0; i < dscp_num; i++) {
+		descp->next_descp = set_start_cmd(1);
+		descp->srcaddr = dma_src + COUTN_TRANSFER * i;
+		descp->dstaddr = dma_dst + COUTN_TRANSFER * i;
+		descp->commandinfo = set_cmd_info(COUTN_TRANSFER);
+		descp++;
+	}
+	descp--;
+	descp->next_descp = set_start_cmd(0);
+	descp->commandinfo = set_cmd_info(other_num);
+
+
+	val = set_start_cmd(1);
+	val |= (unsigned int)(dma->descp);
+	local_irq_disable();
+	__raw_writel(val, dma->dma_reg + GDMA_GDGA);
+
+	val = __raw_readl(GDMA_INTCS);
+	val |= (ENTC0F|ENTC1F);
+	__raw_writel(val, GDMA_INTCS);
+	local_irq_enable();
+
+	return 0;
+}
+EXPORT_SYMBOL(nuc900_start_dma);
+
+void __init nuc900_init_dma(void)
+{
+	unsigned	i, ret;
+	struct nuc900_dma  *dma_channel;
+	spin_lock_init(&dma_chan_lock);
+	for (i = 0; i < NUC900_DMA_CHANNELS; i++) {
+		dma_channel = &dma_chan[i];
+		dma_channel->dma_reg = DMA_BASE + i * CHANNELINERV;
+		dma_channel->device = NULL;
+	}
+	ret = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
+			IRQF_DISABLED, NULL, NULL);
+	if (ret)
+		printk(KERN_ERR "register dma interrupt error: %d\n", ret);
+	dmachan0 = &dma_chan[0];
+	dmachan1 = &dma_chan[1];
+}
diff -uNr b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile
a/arch/arm/mach-w90x900/Makefile
--- b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile	2009-11-20
06:32:38.000000000 +0800
+++ a/arch/arm/mach-w90x900/Makefile	2009-12-06 12:34:47.000000000 +0800
@@ -5,7 +5,7 @@
 # Object file lists.

 obj-y				:= irq.o time.o mfp.o gpio.o clock.o
-obj-y				+= clksel.o dev.o cpu.o
+obj-y				+= clksel.o dev.o cpu.o dma.o
 # W90X900 CPU support files

 obj-$(CONFIG_CPU_W90P910)	+= nuc910.o

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-08 15:47           ` Hu Ruihuan
@ 2009-12-09 14:50             ` Wan ZongShun
  2009-12-09 15:37               ` Hu Ruihuan
  0 siblings, 1 reply; 12+ messages in thread
From: Wan ZongShun @ 2009-12-09 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Hu,

Thanks a lot for your patch, a comment below.

2009/12/8 Hu Ruihuan <specter118@gmail.com>:
> Hi Wan,
> ?I am sorry to make such a stupid mistake. The correct patch below.
>
> Signed-off-by: Hu Ruihuan <specter118@gmail.com>
> ---
> diff -uNr b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c
> a/arch/arm/mach-w90x900/dma.c
> --- b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c ? ? ?1970-01-01
> 08:00:00.000000000 +0800
> +++ a/arch/arm/mach-w90x900/dma.c ? ? ? 2009-12-08 23:34:39.000000000 +0800
> @@ -0,0 +1,295 @@
> +/*
> + * arch/arm/mach-w90p910/dma.c
> + *
> + * Support functions for the w90p910 internal DMA channels.
> + *
> + * Wan Zongshun <mcuos.com@gmail.com>
> + * Hu Ruihuan <specter118@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/init.h>
> +#include <linux/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <asm/system.h>
> +#include <asm/irq.h>
> +#include <asm/atomic.h>
> +#include <mach/hardware.h>
> +
> +#define NUC900_DMA_CHANNELS ? ? ? ? ? ? ? ? ? ?(2)
> +#define DMA_BASE ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (W90X900_VA_GDMA)
> +#define GDMA_INTCS ? ? ? ? ? ? ? ? ? ? ? ? ? ? (DMA_BASE + 0xa0)
> +#define GDMA_GDGA ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x1c)
> +#define TC0F ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01 << 8)
> +#define TC1F ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01 << 10)
> +#define ENTC0F ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01)
> +#define ENTC1F ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01 << 2)
> +
> +#define GDMAEN ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01)
> +#define GDMAMS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x03 << 2)
> +#define DADIR ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01 << 4)
> +#define SADIR ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01 << 5)
> +#define DAFIX ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01 << 6)
> +#define SAFIX ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01 << 7)
> +#define D_INTS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01 << 10)
> +#define TWSMASK ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x03 << 12)
> +#define TWS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x02 << 12)
> +
> +#define RUN ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01 << 3)
> +#define NON_DSCRIP ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x01 << 2)
> +#define ORDEN ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01 << 1)
> +#define RESET ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x01)
> +#define DSCRIPMASK ? ? ? ? ? ? ? ? ? ? ? ? ? ? (0x0F)
> +#define CMDINFOMASK ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0x03FFF)
> +
> +#define COUTN_TRANSFER ? ? ? ? ? ? ? ? ? ? ? ? (0x1000)/*count[13:0]=1024*/
> +#define CHANNELINERV ? ? ? ? ? ? ? ? ? ? ? ? ? (0x20)
> +
> +typedef void (*dma_callback_t)(void *data);
> +
> +struct nuc900_dma_descp {
> + ? ? ? unsigned int next_descp;
> + ? ? ? unsigned int srcaddr;
> + ? ? ? unsigned int dstaddr;
> + ? ? ? unsigned int commandinfo;
> +};
> +
> +struct nuc900_dma {
> + ? ? ? const char *device; ? ? ? ? ? ? /* this channel device, 0 ?if unused */
> + ? ? ? dma_callback_t callback; ? ? ? ?/* to call when DMA completes */
> + ? ? ? void __iomem *dma_reg;
> + ? ? ? void *data; ? ? ? ? ? ? ? ? ? ? /* ... with private data ptr */
> + ? ? ? struct nuc900_dma_descp *descp;
> +};
> +
> +static struct nuc900_dma ?dma_chan[NUC900_DMA_CHANNELS];
> +static struct nuc900_dma *dmachan0, *dmachan1;
> +static atomic_t ?shared_irq_using;
> +static DEFINE_SPINLOCK(dma_chan_lock);
> +static struct nuc900_dma *register_dmachan_fromname(const char *dev_name,
> + ? ? ? ? ? ? ? ? ? ? ? unsigned int *irq_request)
> +{
> + ? ? ? struct nuc900_dma *ret = NULL;
> +
> + ? ? ? BUG_ON(!dev_name);
> +
> +
> + ? ? ? if (!(dmachan0->device) && !(dmachan1->device)) {
> + ? ? ? ? ? ? ? ret = dmachan0;
> + ? ? ? ? ? ? ? *irq_request = 1;
> + ? ? ? } else if ((dmachan0->device) && !(dmachan1->device)) {
> + ? ? ? ? ? ? ? ? ? ? ? if (strcmp(dmachan0->device, dev_name) == 0)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret = ERR_PTR(-EBUSY);
> + ? ? ? ? ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret = dmachan1;
> + ? ? ? } else if ((dmachan1->device) && !(dmachan0->device)) {
> + ? ? ? ? ? ? ? ? ? ? ? if (strcmp(dmachan1->device, dev_name) == 0)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret = ERR_PTR(-EBUSY);
> + ? ? ? ? ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret = dmachan0;
> + ? ? ? } else
> + ? ? ? ? ? ? ? ret = ERR_PTR(-EBUSY);
> +
> + ? ? ? return ret;
> +
> +}
> +
> +static void match_dmachan_fromname(const char *dev_name,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct nuc900_dma ?**dma)
> +{
> + ? ? ? BUG_ON(!dev_name);
> +
> + ? ? ? if (dmachan1->device) {
> + ? ? ? ? ? ? ? if (strcmp(dmachan1->device, dev_name) == 0)
> + ? ? ? ? ? ? ? ? ? ? ? *dma = dmachan1;
> + ? ? ? } else if (dmachan0->device) {
> + ? ? ? ? ? ? ? if (strcmp(dmachan0->device, dev_name) == 0)
> + ? ? ? ? ? ? ? ? ? ? ? *dma = dmachan0;
> + ? ? ? }
> +}
> +
> +static irqreturn_t dma_irq_handler(int irq, void *dev_id)
> +{
> + ? ? ? int status;
> + ? ? ? local_irq_disable();
> + ? ? ? status = __raw_readl(GDMA_GDGA) & (TC0F|TC1F);
> + ? ? ? __raw_writel(~status, GDMA_GDGA);
> + ? ? ? local_irq_enable();
> +
> + ? ? ? if (status & TC0F)
> + ? ? ? ? ? ? ? dmachan0->callback(dmachan0->data);
> + ? ? ? if (status & TC1F)
> + ? ? ? ? ? ? ? dmachan1->callback(dmachan1->data);
> +
> + ? ? ? return IRQ_HANDLED;
> +}
> +
> +int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? void *data)
> +{
> + ? ? ? struct nuc900_dma ?*dma = NULL;
> + ? ? ? int err, irq_request;
> + ? ? ? err = 0;
> + ? ? ? irq_request = 0;
> + ? ? ? spin_lock(&dma_chan_lock);
> + ? ? ? dma = register_dmachan_fromname(dev_name, &irq_request);
> +
> + ? ? ? if (IS_ERR(dma)) {
> + ? ? ? ? ? ? ? err = ERR_PTR(dma);

         hi, I think it should be PTR_ERR rather than ERR_PTR, such as:

                  err = PTR_ERR(dma);

> + ? ? ? ? ? ? ? spin_unlock(&dma_chan_lock);
> + ? ? ? ? ? ? ? return err;
> + ? ? ? }
> + ? ? ? dma->device = dev_name;
> + ? ? ? atomic_inc(&shared_irq_using);
> + ? ? ? dma->callback = callback;
> + ? ? ? dma->data = data;
> + ? ? ? spin_unlock(&dma_chan_lock);
> + ? ? ? return 0;
> +}
> +EXPORT_SYMBOL(nuc900_request_dma);
> +
> +int nuc900_free_dma(const char *dev_name)
> +{
> + ? ? ? struct nuc900_dma ?*dma = NULL;
> +
> + ? ? ? BUG_ON(!dev_name);
> + ? ? ? WARN_ON(shared_irq_using.counter == 0);
> + ? ? ? spin_lock(&dma_chan_lock);
> + ? ? ? match_dmachan_fromname(dev_name, &dma);
> +
> + ? ? ? if (!dma)
> + ? ? ? ? ? ? ? return -ENXIO;
> +
> + ? ? ? dma->device = NULL;
> + ? ? ? spin_unlock(&dma_chan_lock);
> +
> + ? ? ? atomic_dec(&shared_irq_using);
> +
> + ? ? ? kzfree(dma->descp);
> + ? ? ? return 0;
> +}
> +EXPORT_SYMBOL(nuc900_free_dma);
> +
> +static unsigned int set_start_cmd(unsigned int start)
> +{
> + ? ? ? unsigned int dscp_cmd;
> +
> + ? ? ? dscp_cmd = 0;
> +
> + ? ? ? if (start) {
> + ? ? ? ? ? ? ? dscp_cmd = (ORDEN|RUN);
> + ? ? ? ? ? ? ? dscp_cmd &= ~(NON_DSCRIP|RESET);
> + ? ? ? } else {
> + ? ? ? ? ? ? ? dscp_cmd = (NON_DSCRIP);
> + ? ? ? }
> + ? ? ? ? ? ? ? dscp_cmd &= DSCRIPMASK;
> +
> + ? ? ? return dscp_cmd;
> +}
> +
> +static unsigned int set_cmd_info(unsigned int countsize)
> +{
> + ? ? ? unsigned int cmd_info;
> +
> + ? ? ? cmd_info = (countsize >> 2);
> +
> + ? ? ? cmd_info = (((cmd_info & CMDINFOMASK) << 18)|GDMAEN|D_INTS);
> + ? ? ? cmd_info &= ~(GDMAMS|DADIR|SADIR|DAFIX|SAFIX|TWSMASK);
> + ? ? ? cmd_info |= TWS;
> +
> + ? ? ? return cmd_info;
> +
> +}
> +
> +static unsigned int get_descplist_num(unsigned int size, unsigned int *leave)
> +{
> + ? ? ? unsigned int dscp_num, other_num;
> +
> + ? ? ? dscp_num = 0;
> + ? ? ? other_num = 0;
> +
> + ? ? ? dscp_num = size / COUTN_TRANSFER;
> + ? ? ? other_num = size % COUTN_TRANSFER;
> +
> + ? ? ? if (other_num)
> + ? ? ? ? ? ? ? dscp_num += 1;
> +
> + ? ? ? *leave = other_num;
> +
> + ? ? ? return dscp_num;
> +
> +}
> +
> +int nuc900_start_dma(const char *dev_name, dma_addr_t dma_src,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dma_addr_t dma_dst, unsigned int size)
> +{
> + ? ? ? struct nuc900_dma_descp *descp = NULL;
> + ? ? ? struct nuc900_dma ?*dma = NULL;
> + ? ? ? unsigned int i, dscp_num, other_num, val;
> +
> + ? ? ? BUG_ON((!size|!dev_name));
> +
> + ? ? ? match_dmachan_fromname(dev_name, &dma);
> +
> + ? ? ? if (!dma)
> + ? ? ? ? ? ? ? return -ENXIO;
> +
> + ? ? ? dscp_num = get_descplist_num(size, &other_num);
> +
> + ? ? ? descp = kzalloc(dscp_num * sizeof(struct nuc900_dma), GFP_KERNEL);
> +
> + ? ? ? if (!descp)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? dma->descp = descp;
> +
> + ? ? ? for (i = 0; i < dscp_num; i++) {
> + ? ? ? ? ? ? ? descp->next_descp = set_start_cmd(1);
> + ? ? ? ? ? ? ? descp->srcaddr = dma_src + COUTN_TRANSFER * i;
> + ? ? ? ? ? ? ? descp->dstaddr = dma_dst + COUTN_TRANSFER * i;
> + ? ? ? ? ? ? ? descp->commandinfo = set_cmd_info(COUTN_TRANSFER);
> + ? ? ? ? ? ? ? descp++;
> + ? ? ? }
> + ? ? ? descp--;
> + ? ? ? descp->next_descp = set_start_cmd(0);
> + ? ? ? descp->commandinfo = set_cmd_info(other_num);
> +
> +
> + ? ? ? val = set_start_cmd(1);
> + ? ? ? val |= (unsigned int)(dma->descp);
> + ? ? ? local_irq_disable();
> + ? ? ? __raw_writel(val, dma->dma_reg + GDMA_GDGA);
> +
> + ? ? ? val = __raw_readl(GDMA_INTCS);
> + ? ? ? val |= (ENTC0F|ENTC1F);
> + ? ? ? __raw_writel(val, GDMA_INTCS);
> + ? ? ? local_irq_enable();
> +
> + ? ? ? return 0;
> +}
> +EXPORT_SYMBOL(nuc900_start_dma);
> +
> +void __init nuc900_init_dma(void)
> +{
> + ? ? ? unsigned ? ? ? ?i, ret;
> + ? ? ? struct nuc900_dma ?*dma_channel;
> + ? ? ? spin_lock_init(&dma_chan_lock);
> + ? ? ? for (i = 0; i < NUC900_DMA_CHANNELS; i++) {
> + ? ? ? ? ? ? ? dma_channel = &dma_chan[i];
> + ? ? ? ? ? ? ? dma_channel->dma_reg = DMA_BASE + i * CHANNELINERV;
> + ? ? ? ? ? ? ? dma_channel->device = NULL;
> + ? ? ? }
> + ? ? ? ret = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
> + ? ? ? ? ? ? ? ? ? ? ? IRQF_DISABLED, NULL, NULL);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? printk(KERN_ERR "register dma interrupt error: %d\n", ret);
> + ? ? ? dmachan0 = &dma_chan[0];
> + ? ? ? dmachan1 = &dma_chan[1];
> +}
> diff -uNr b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile
> a/arch/arm/mach-w90x900/Makefile
> --- b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile ? 2009-11-20
> 06:32:38.000000000 +0800
> +++ a/arch/arm/mach-w90x900/Makefile ? ?2009-12-06 12:34:47.000000000 +0800
> @@ -5,7 +5,7 @@
> ?# Object file lists.
>
> ?obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?:= irq.o time.o mfp.o gpio.o clock.o
> -obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= clksel.o dev.o cpu.o
> +obj-y ? ? ? ? ? ? ? ? ? ? ? ? ?+= clksel.o dev.o cpu.o dma.o
> ?# W90X900 CPU support files
>
> ?obj-$(CONFIG_CPU_W90P910) ? ? ?+= nuc910.o
>



-- 
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-09 14:50             ` Wan ZongShun
@ 2009-12-09 15:37               ` Hu Ruihuan
  2009-12-10 10:20                 ` Russell King - ARM Linux
  0 siblings, 1 reply; 12+ messages in thread
From: Hu Ruihuan @ 2009-12-09 15:37 UTC (permalink / raw)
  To: linux-arm-kernel

HI, Wan
  I made an update below.

Signed-off-by: Hu Ruihuan <specter118@gmail.com>
---
diff -uNr b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c
a/arch/arm/mach-w90x900/dma.c
--- b/linux-2.6.32-rc8/arch/arm/mach-w90x900/dma.c	1970-01-01
08:00:00.000000000 +0800
+++ a/arch/arm/mach-w90x900/dma.c	2009-12-08 23:34:39.000000000 +0800
@@ -0,0 +1,295 @@
+/*
+ * arch/arm/mach-w90p910/dma.c
+ *
+ * Support functions for the w90p910 internal DMA channels.
+ *
+ * Wan Zongshun <mcuos.com@gmail.com>
+ * Hu Ruihuan <specter118@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <mach/hardware.h>
+
+#define NUC900_DMA_CHANNELS			(2)
+#define DMA_BASE 				(W90X900_VA_GDMA)
+#define GDMA_INTCS				(DMA_BASE + 0xa0)
+#define GDMA_GDGA				(0x1c)
+#define TC0F					(0x01 << 8)
+#define TC1F					(0x01 << 10)
+#define ENTC0F					(0x01)
+#define ENTC1F					(0x01 << 2)
+
+#define GDMAEN				        (0x01)
+#define GDMAMS					(0x03 << 2)
+#define DADIR					(0x01 << 4)
+#define SADIR					(0x01 << 5)
+#define DAFIX					(0x01 << 6)
+#define SAFIX					(0x01 << 7)
+#define D_INTS					(0x01 << 10)
+#define TWSMASK					(0x03 << 12)
+#define TWS					(0x02 << 12)
+
+#define RUN				        (0x01 << 3)
+#define NON_DSCRIP				(0x01 << 2)
+#define ORDEN					(0x01 << 1)
+#define RESET					(0x01)
+#define DSCRIPMASK			        (0x0F)
+#define CMDINFOMASK				(0x03FFF)
+
+#define COUTN_TRANSFER				(0x1000)/*count[13:0]=1024*/
+#define CHANNELINERV				(0x20)
+
+typedef void (*dma_callback_t)(void *data);
+
+struct nuc900_dma_descp {
+	unsigned int next_descp;
+	unsigned int srcaddr;
+	unsigned int dstaddr;
+	unsigned int commandinfo;
+};
+
+struct nuc900_dma {
+	const char *device;		/* this channel device, 0  if unused */
+	dma_callback_t callback;	/* to call when DMA completes */
+	void __iomem *dma_reg;
+	void *data;			/* ... with private data ptr */
+	struct nuc900_dma_descp *descp;
+};
+
+static struct nuc900_dma  dma_chan[NUC900_DMA_CHANNELS];
+static struct nuc900_dma *dmachan0, *dmachan1;
+static atomic_t  shared_irq_using;
+static DEFINE_SPINLOCK(dma_chan_lock);
+static struct nuc900_dma *register_dmachan_fromname(const char *dev_name,
+			unsigned int *irq_request)
+{
+	struct nuc900_dma *ret = NULL;
+
+	BUG_ON(!dev_name);
+
+
+	if (!(dmachan0->device) && !(dmachan1->device)) {
+		ret = dmachan0;
+		*irq_request = 1;
+	} else if ((dmachan0->device) && !(dmachan1->device)) {
+			if (strcmp(dmachan0->device, dev_name) == 0)
+				ret = ERR_PTR(-EBUSY);
+			else
+				ret = dmachan1;
+	} else if ((dmachan1->device) && !(dmachan0->device)) {
+			if (strcmp(dmachan1->device, dev_name) == 0)
+				ret = ERR_PTR(-EBUSY);
+			else
+				ret = dmachan0;
+	} else
+		ret = ERR_PTR(-EBUSY);
+
+	return ret;
+
+}
+
+static void match_dmachan_fromname(const char *dev_name,
+					struct nuc900_dma  **dma)
+{
+	BUG_ON(!dev_name);
+
+	if (dmachan1->device) {
+		if (strcmp(dmachan1->device, dev_name) == 0)
+			*dma = dmachan1;
+	} else if (dmachan0->device) {
+		if (strcmp(dmachan0->device, dev_name) == 0)
+			*dma = dmachan0;
+	}
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+{
+	int status;
+	local_irq_disable();
+	status = __raw_readl(GDMA_GDGA) & (TC0F|TC1F);
+	__raw_writel(~status, GDMA_GDGA);
+	local_irq_enable();
+
+	if (status & TC0F)
+		dmachan0->callback(dmachan0->data);
+	if (status & TC1F)
+		dmachan1->callback(dmachan1->data);
+
+	return IRQ_HANDLED;
+}
+
+int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
+								void *data)
+{
+	struct nuc900_dma  *dma = NULL;
+	int err, irq_request;
+	err = 0;
+	irq_request = 0;
+	spin_lock(&dma_chan_lock);
+	dma = register_dmachan_fromname(dev_name, &irq_request);
+
+	if (IS_ERR(dma)) {
+		err = PTR_ERR(dma);
+		spin_unlock(&dma_chan_lock);
+		return err;
+	}
+	dma->device = dev_name;
+	atomic_inc(&shared_irq_using);
+	dma->callback = callback;
+	dma->data = data;
+	spin_unlock(&dma_chan_lock);
+	return 0;
+}
+EXPORT_SYMBOL(nuc900_request_dma);
+
+int nuc900_free_dma(const char *dev_name)
+{
+	struct nuc900_dma  *dma = NULL;
+
+	BUG_ON(!dev_name);
+	WARN_ON(shared_irq_using.counter == 0);
+	spin_lock(&dma_chan_lock);
+	match_dmachan_fromname(dev_name, &dma);
+
+	if (!dma)
+		return -ENXIO;
+
+	dma->device = NULL;
+	spin_unlock(&dma_chan_lock);
+
+	atomic_dec(&shared_irq_using);
+
+	kzfree(dma->descp);
+	return 0;
+}
+EXPORT_SYMBOL(nuc900_free_dma);
+
+static unsigned int set_start_cmd(unsigned int start)
+{
+	unsigned int dscp_cmd;
+
+	dscp_cmd = 0;
+
+	if (start) {
+		dscp_cmd = (ORDEN|RUN);
+		dscp_cmd &= ~(NON_DSCRIP|RESET);
+	} else {
+		dscp_cmd = (NON_DSCRIP);
+	}
+		dscp_cmd &= DSCRIPMASK;
+
+	return dscp_cmd;
+}
+
+static unsigned int set_cmd_info(unsigned int countsize)
+{
+	unsigned int cmd_info;
+
+	cmd_info = (countsize >> 2);
+
+	cmd_info = (((cmd_info & CMDINFOMASK) << 18)|GDMAEN|D_INTS);
+	cmd_info &= ~(GDMAMS|DADIR|SADIR|DAFIX|SAFIX|TWSMASK);
+	cmd_info |= TWS;
+
+	return cmd_info;
+
+}
+
+static unsigned int get_descplist_num(unsigned int size, unsigned int *leave)
+{
+	unsigned int dscp_num, other_num;
+
+	dscp_num = 0;
+	other_num = 0;
+
+	dscp_num = size / COUTN_TRANSFER;
+	other_num = size % COUTN_TRANSFER;
+
+	if (other_num)
+		dscp_num += 1;
+
+	*leave = other_num;
+
+	return dscp_num;
+
+}
+
+int nuc900_start_dma(const char *dev_name, dma_addr_t dma_src,
+					dma_addr_t dma_dst, unsigned int size)
+{
+	struct nuc900_dma_descp *descp = NULL;
+	struct nuc900_dma  *dma = NULL;
+	unsigned int i, dscp_num, other_num, val;
+
+	BUG_ON((!size|!dev_name));
+
+	match_dmachan_fromname(dev_name, &dma);
+
+	if (!dma)
+		return -ENXIO;
+
+	dscp_num = get_descplist_num(size, &other_num);
+
+	descp = kzalloc(dscp_num * sizeof(struct nuc900_dma), GFP_KERNEL);
+
+	if (!descp)
+		return -ENOMEM;
+
+	dma->descp = descp;
+
+	for (i = 0; i < dscp_num; i++) {
+		descp->next_descp = set_start_cmd(1);
+		descp->srcaddr = dma_src + COUTN_TRANSFER * i;
+		descp->dstaddr = dma_dst + COUTN_TRANSFER * i;
+		descp->commandinfo = set_cmd_info(COUTN_TRANSFER);
+		descp++;
+	}
+	descp--;
+	descp->next_descp = set_start_cmd(0);
+	descp->commandinfo = set_cmd_info(other_num);
+
+
+	val = set_start_cmd(1);
+	val |= (unsigned int)(dma->descp);
+	local_irq_disable();
+	__raw_writel(val, dma->dma_reg + GDMA_GDGA);
+
+	val = __raw_readl(GDMA_INTCS);
+	val |= (ENTC0F|ENTC1F);
+	__raw_writel(val, GDMA_INTCS);
+	local_irq_enable();
+
+	return 0;
+}
+EXPORT_SYMBOL(nuc900_start_dma);
+
+void __init nuc900_init_dma(void)
+{
+	unsigned	i, ret;
+	struct nuc900_dma  *dma_channel;
+	spin_lock_init(&dma_chan_lock);
+	for (i = 0; i < NUC900_DMA_CHANNELS; i++) {
+		dma_channel = &dma_chan[i];
+		dma_channel->dma_reg = DMA_BASE + i * CHANNELINERV;
+		dma_channel->device = NULL;
+	}
+	ret = request_irq(IRQ_GDMAGROUP, dma_irq_handler, IRQF_SHARED|
+			IRQF_DISABLED, NULL, NULL);
+	if (ret)
+		printk(KERN_ERR "register dma interrupt error: %d\n", ret);
+	dmachan0 = &dma_chan[0];
+	dmachan1 = &dma_chan[1];
+}
diff -uNr b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile
a/arch/arm/mach-w90x900/Makefile
--- b/linux-2.6.32-rc8/arch/arm/mach-w90x900/Makefile	2009-11-20
06:32:38.000000000 +0800
+++ a/arch/arm/mach-w90x900/Makefile	2009-12-06 12:34:47.000000000 +0800
@@ -5,7 +5,7 @@
 # Object file lists.

 obj-y				:= irq.o time.o mfp.o gpio.o clock.o
-obj-y				+= clksel.o dev.o cpu.o
+obj-y				+= clksel.o dev.o cpu.o dma.o
 # W90X900 CPU support files

 obj-$(CONFIG_CPU_W90P910)	+= nuc910.o

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform
  2009-12-09 15:37               ` Hu Ruihuan
@ 2009-12-10 10:20                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 12+ messages in thread
From: Russell King - ARM Linux @ 2009-12-10 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 09, 2009 at 11:37:50PM +0800, Hu Ruihuan wrote:
> +static void match_dmachan_fromname(const char *dev_name,
> +					struct nuc900_dma  **dma)
> +{
> +	BUG_ON(!dev_name);
> +
> +	if (dmachan1->device) {
> +		if (strcmp(dmachan1->device, dev_name) == 0)
> +			*dma = dmachan1;
> +	} else if (dmachan0->device) {
> +		if (strcmp(dmachan0->device, dev_name) == 0)
> +			*dma = dmachan0;
> +	}
> +}

Never write functions like this without explaination of why you're doing
it this way: having a void function returning something through a
double pointer is just silly, and leads to bugs (when someone forgets
to NULL-initialize before-hand.)

static struct nuc900_dma *match_dmachan_fromname(const char *dev_name)
{
	BUG_ON(!dev_name);

	if (dmachan1->device) {
		if (strcmp(dmachan1->device, dev_name) == 0)
			return dmachan1;
	} else if (dmachan0->device) {
		if (strcmp(dmachan0->device, dev_name) == 0)
			return dmachan0;
	}
	return NULL;
}

This way, whenever you do:

	dmachan = match_dmachan_fromname(foo);

you know that dmachan will always be initialized, whereas:

	match_dmachan_fromname(foo, &dmachan);

there's little to tell the compiler that dmachan will be initialized -
in fact, the compiler _can't_ tell you whether you're possibly using it
without it having been initialized.

> +int nuc900_request_dma(const char *dev_name, dma_callback_t callback,
> +								void *data)
> +{
> +	struct nuc900_dma  *dma = NULL;
> +	int err, irq_request;
> +	err = 0;
> +	irq_request = 0;
> +	spin_lock(&dma_chan_lock);
> +	dma = register_dmachan_fromname(dev_name, &irq_request);

It seems that the irq_request handling is now unnecessary, please remove.

> +	if (IS_ERR(dma)) {
> +		err = PTR_ERR(dma);
> +		spin_unlock(&dma_chan_lock);
> +		return err;
> +	}
> +	dma->device = dev_name;
> +	atomic_inc(&shared_irq_using);

shared_irq_using is not required anymore.

> +	dma->callback = callback;
> +	dma->data = data;
> +	spin_unlock(&dma_chan_lock);
> +	return 0;
> +}
> +EXPORT_SYMBOL(nuc900_request_dma);
> +
> +int nuc900_free_dma(const char *dev_name)
> +{
> +	struct nuc900_dma  *dma = NULL;
> +
> +	BUG_ON(!dev_name);
> +	WARN_ON(shared_irq_using.counter == 0);

This is buggy, never go inside an 'atomic' object - use the accessor
functions.  In any case, shared_irq_using is not required so this can
be deleted.

> +	spin_lock(&dma_chan_lock);
> +	match_dmachan_fromname(dev_name, &dma);
> +
> +	if (!dma)
> +		return -ENXIO;
> +
> +	dma->device = NULL;
> +	spin_unlock(&dma_chan_lock);
> +
> +	atomic_dec(&shared_irq_using);

Can be removed.

> +
> +	kzfree(dma->descp);
> +	return 0;
> +}
> +EXPORT_SYMBOL(nuc900_free_dma);
> +
> +static unsigned int set_start_cmd(unsigned int start)
> +{
> +	unsigned int dscp_cmd;
> +
> +	dscp_cmd = 0;
> +
> +	if (start) {
> +		dscp_cmd = (ORDEN|RUN);
> +		dscp_cmd &= ~(NON_DSCRIP|RESET);
> +	} else {
> +		dscp_cmd = (NON_DSCRIP);
> +	}
> +		dscp_cmd &= DSCRIPMASK;

Weird formatting - is this correctly placed?  It looks like it should
be within the else { } clause.

> +
> +	return dscp_cmd;
> +}

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-12-10 10:20 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-26 10:42 [PATCH V2] ARM: NUC900: add GDMA driver support for nuc900 platform Hu Ruihuan
2009-11-29 12:03 ` Wan ZongShun
2009-11-29 12:16 ` Russell King - ARM Linux
2009-12-07 15:53   ` Hu Ruihuan
2009-12-07 17:18     ` Russell King - ARM Linux
2009-12-07 18:11       ` Hu Ruihuan
2009-12-07 18:39         ` Russell King - ARM Linux
2009-12-08  3:03         ` Wan ZongShun
2009-12-08 15:47           ` Hu Ruihuan
2009-12-09 14:50             ` Wan ZongShun
2009-12-09 15:37               ` Hu Ruihuan
2009-12-10 10:20                 ` Russell King - ARM Linux

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.