public inbox for linux-sh@vger.kernel.org
 help / color / mirror / Atom feed
From: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
To: linux-sh@vger.kernel.org
Subject: [RFC][PATCH] sh: override DMA interrupt handler to dma-sh driver
Date: Mon, 29 Sep 2008 09:26:45 +0000	[thread overview]
Message-ID: <48E09F55.4030406@renesas.com> (raw)

Dma-sh has fixed interrupt handler and cannot register
an interrupt for exclusive use of the device with dma.

I added a handler to sh_dmac_request_dma and reviced it
to be able to appoint a handler.

Signed-off-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@nigauri.org>
---
 arch/sh/drivers/dma/Kconfig       |    2 +-
 arch/sh/drivers/dma/dma-api.c     |   63 +++++++++++++++++++++++++-----------
 arch/sh/drivers/dma/dma-pvr2.c    |    2 +-
 arch/sh/drivers/dma/dma-sh.c      |   38 ++++++++++++----------
 arch/sh/drivers/dma/dma-sh.h      |   46 +++++++++++++++++++--------
 arch/sh/drivers/dma/dmabrg.c      |    2 +-
 arch/sh/include/asm/dma.h         |   36 +++++++++++++++++---
 arch/sh/include/cpu-sh4/cpu/dma.h |    9 +++++-
 8 files changed, 137 insertions(+), 61 deletions(-)

diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 0193636..0c4ee21 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -12,7 +12,7 @@ config SH_DMA
 config NR_ONCHIP_DMA_CHANNELS
 	int
 	depends on SH_DMA
-	default "6" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721
+	default "6" if CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721 || CPU_SUBTYPE_SH7763
 	default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
 	default "12" if CPU_SUBTYPE_SH7780
 	default "4"
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c
index 727126e..27831a1 100644
--- a/arch/sh/drivers/dma/dma-api.c
+++ b/arch/sh/drivers/dma/dma-api.c
@@ -126,7 +126,8 @@ static int search_cap(const char **haystack, const char *needle)
  * case they can never be allocated using this API, and so
  * request_dma() must be used specifying the channel number.
  */
-int request_dma_bycap(const char **dmac, const char **caps, const char *dev_id)
+int request_dma_bycap(const char **dmac, const char **caps,
+	const char *dev_id, irq_handler_t handler, void *data)
 {
 	unsigned int found = 0;
 	struct dma_info *info;
@@ -135,6 +136,9 @@ int request_dma_bycap(const char **dmac, const char **caps, const char *dev_id)

 	BUG_ON(!dmac || !caps);

+	if(!handler||!data)
+		return -EINVAL;
+
 	list_for_each_entry(info, &registered_dmac_list, list)
 		if (strcmp(*dmac, info->name) = 0) {
 			found = 1;
@@ -149,20 +153,19 @@ int request_dma_bycap(const char **dmac, const char **caps, const char *dev_id)

 		if (unlikely(!channel->caps))
 			continue;
-
 		for (p = caps; *p; p++) {
 			if (!search_cap(channel->caps, *p))
 				break;
-			if (request_dma(channel->chan, dev_id) = 0)
+
+			if (request_dma(channel->chan, dev_id, handler, data) = 0)
 				return channel->chan;
 		}
 	}
-
 	return -EINVAL;
 }
 EXPORT_SYMBOL(request_dma_bycap);

-int dmac_search_free_channel(const char *dev_id)
+int dmac_search_free_channel(void)
 {
 	struct dma_channel *channel = { 0 };
 	struct dma_info *info = get_dma_info(0);
@@ -177,32 +180,26 @@ int dmac_search_free_channel(const char *dev_id)
 			break;
 	}

-	if (info->ops->request) {
-		int result = info->ops->request(channel);
-		if (result)
-			return result;
-
-		atomic_set(&channel->busy, 1);
-		return channel->chan;
-	}
-
-	return -ENOSYS;
+	return channel->chan;
 }
+EXPORT_SYMBOL(dmac_search_free_channel);

-int request_dma(unsigned int chan, const char *dev_id)
+int request_dma(unsigned int chan, const char *dev_id,
+	irq_handler_t handler, void *data)
 {
 	struct dma_channel *channel = { 0 };
 	struct dma_info *info = get_dma_info(chan);
 	int result;

 	channel = get_dma_channel(chan);
+
 	if (atomic_xchg(&channel->busy, 1))
 		return -EBUSY;

 	strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id));

 	if (info->ops->request) {
-		result = info->ops->request(channel);
+		result = info->ops->request(channel, handler, data);
 		if (result)
 			atomic_set(&channel->busy, 0);

@@ -213,13 +210,13 @@ int request_dma(unsigned int chan, const char *dev_id)
 }
 EXPORT_SYMBOL(request_dma);

-void free_dma(unsigned int chan)
+void free_dma(unsigned int chan, void *data)
 {
 	struct dma_info *info = get_dma_info(chan);
 	struct dma_channel *channel = get_dma_channel(chan);

 	if (info->ops->free)
-		info->ops->free(channel);
+		info->ops->free(channel, data);

 	atomic_set(&channel->busy, 0);
 }
@@ -295,6 +292,34 @@ int dma_xfer(unsigned int chan, unsigned long from,
 }
 EXPORT_SYMBOL(dma_xfer);

+int dma_start(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = get_dma_channel(chan);
+	
+	if( info->ops->start ) {
+		info->ops->start(channel);
+		return 0;
+	}
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(dma_start);
+
+int dma_stop(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = get_dma_channel(chan);
+
+	if( info->ops->stop ){
+		info->ops->stop(channel);
+		return 0;
+	}
+
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(dma_stop);
+
 int dma_extend(unsigned int chan, unsigned long op, void *param)
 {
 	struct dma_info *info = get_dma_info(chan);
diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c
index 391cbe1..2016e88 100644
--- a/arch/sh/drivers/dma/dma-pvr2.c
+++ b/arch/sh/drivers/dma/dma-pvr2.c
@@ -89,7 +89,7 @@ static struct dma_info pvr2_dma_info = {
 static int __init pvr2_dma_init(void)
 {
 	setup_irq(HW_EVENT_PVR2_DMA, &pvr2_dma_irq);
-	request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade");
+	request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade",NULL, NULL);

 	return register_dmac(&pvr2_dma_info);
 }
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index b2ffe64..69cb807 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -28,6 +28,7 @@ static int dmte_irq_map[] = {
     defined(CONFIG_CPU_SUBTYPE_SH7721)  ||	\
     defined(CONFIG_CPU_SUBTYPE_SH7751R) ||	\
     defined(CONFIG_CPU_SUBTYPE_SH7760)  ||	\
+    defined(CONFIG_CPU_SUBTYPE_SH7763)  ||	\
     defined(CONFIG_CPU_SUBTYPE_SH7709)  ||	\
     defined(CONFIG_CPU_SUBTYPE_SH7780)
 	DMTE4_IRQ,
@@ -88,18 +89,25 @@ static irqreturn_t dma_tei(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }

-static int sh_dmac_request_dma(struct dma_channel *chan)
+static int sh_dmac_request_dma(struct dma_channel *chan, irq_handler_t handler, void *data)
 {
 	if (unlikely(!(chan->flags & DMA_TEI_CAPABLE)))
 		return 0;

+	if (handler)
+		return request_irq(get_dmte_irq(chan->chan), handler,
+			IRQF_DISABLED, chan->dev_id, data);
+
 	return request_irq(get_dmte_irq(chan->chan), dma_tei,
-			   IRQF_DISABLED, chan->dev_id, chan);
+			IRQF_DISABLED, chan->dev_id, chan);
 }

-static void sh_dmac_free_dma(struct dma_channel *chan)
+static void sh_dmac_free_dma(struct dma_channel *chan, void *data)
 {
-	free_irq(get_dmte_irq(chan->chan), chan);
+	if (data)
+		free_irq(get_dmte_irq(chan->chan), data);
+	else
+		free_irq(get_dmte_irq(chan->chan), chan);
 }

 static int
@@ -116,17 +124,14 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
 	}

 	ctrl_outl(chcr, CHCR[chan->chan]);
-
 	chan->flags |= DMA_CONFIGURED;
 	return 0;
 }

 static void sh_dmac_enable_dma(struct dma_channel *chan)
 {
-	int irq;
-	u32 chcr;
+	u32 chcr= ctrl_inl(CHCR[chan->chan]);

-	chcr = ctrl_inl(CHCR[chan->chan]);
 	chcr |= CHCR_DE;

 	if (chan->flags & DMA_TEI_CAPABLE)
@@ -134,21 +139,15 @@ static void sh_dmac_enable_dma(struct dma_channel *chan)

 	ctrl_outl(chcr, CHCR[chan->chan]);

-	if (chan->flags & DMA_TEI_CAPABLE) {
-		irq = get_dmte_irq(chan->chan);
-		enable_irq(irq);
-	}
+	if (chan->flags & DMA_TEI_CAPABLE)
+		enable_irq(get_dmte_irq(chan->chan));
 }

 static void sh_dmac_disable_dma(struct dma_channel *chan)
 {
-	int irq;
 	u32 chcr;
-
-	if (chan->flags & DMA_TEI_CAPABLE) {
-		irq = get_dmte_irq(chan->chan);
-		disable_irq(irq);
-	}
+	if (chan->flags & DMA_TEI_CAPABLE)
+		disable_irq(get_dmte_irq(chan->chan));

 	chcr = ctrl_inl(CHCR[chan->chan]);
 	chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
@@ -205,6 +204,7 @@ static int sh_dmac_get_dma_residue(struct dma_channel *chan)

 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
     defined(CONFIG_CPU_SUBTYPE_SH7780)
 #define dmaor_read_reg()	ctrl_inw(DMAOR)
 #define dmaor_write_reg(data)	ctrl_outw(data, DMAOR)
@@ -249,6 +249,8 @@ static struct dma_ops sh_dmac_ops = {
 	.get_residue	= sh_dmac_get_dma_residue,
 	.xfer		= sh_dmac_xfer_dma,
 	.configure	= sh_dmac_configure_channel,
+	.start = sh_dmac_enable_dma,
+	.stop = sh_dmac_disable_dma,
 };

 static struct dma_info sh_dmac_info = {
diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h
index b05af34..6cb8269 100644
--- a/arch/sh/drivers/dma/dma-sh.h
+++ b/arch/sh/drivers/dma/dma-sh.h
@@ -28,10 +28,21 @@
 #define SM_DEC	0x00002000
 #define RS_IN	0x00000200
 #define RS_OUT	0x00000300
+#define RS_EXT	0x00000000
+#define RS_AUTO 0x00000400
+#define RS_MOD	0x00000800
 #define TS_BLK	0x00000040
+#define TB_E	0x00000020
 #define CHCR_DE 0x00000001
 #define CHCR_TE 0x00000002
 #define CHCR_IE 0x00000004
+/* Reload / Repert Mode */
+#define RPT_ALL	0x01000000
+#define RPT_DAR	0x02000000
+#define RPT_SAR	0x03000000
+#define RLD_ALL	0x05000000
+#define RLD_DAR	0x06000000
+#define RLD_SAR	0x07000000

 /* DMAOR definitions */
 #define DMAOR_AE	0x00000004
@@ -42,7 +53,7 @@
  * Define the default configuration for dual address memory-memory transfer.
  * The 0x400 value represents auto-request, external->external.
  */
-#define RS_DUAL	(DM_INC | SM_INC | 0x400 | TS_32)
+#define RS_DUAL	(DM_INC | SM_INC | RS_AUTO | TS_32)

 #define MAX_DMAC_CHANNELS	(CONFIG_NR_ONCHIP_DMA_CHANNELS)

@@ -55,20 +66,27 @@
  * basic calculation, unfortunately on other subtypes these are more
  * scattered, so we just leave it unrolled for simplicity.
  */
-#define SAR	((unsigned long[]){SH_DMAC_BASE + 0x00, SH_DMAC_BASE + 0x10, \
-				   SH_DMAC_BASE + 0x20, SH_DMAC_BASE + 0x30, \
-				   SH_DMAC_BASE + 0x50, SH_DMAC_BASE + 0x60})
-#define DAR	((unsigned long[]){SH_DMAC_BASE + 0x04, SH_DMAC_BASE + 0x14, \
-				   SH_DMAC_BASE + 0x24, SH_DMAC_BASE + 0x34, \
-				   SH_DMAC_BASE + 0x54, SH_DMAC_BASE + 0x64})
-#define DMATCR	((unsigned long[]){SH_DMAC_BASE + 0x08, SH_DMAC_BASE + 0x18, \
-				   SH_DMAC_BASE + 0x28, SH_DMAC_BASE + 0x38, \
-				   SH_DMAC_BASE + 0x58, SH_DMAC_BASE + 0x68})
-#define CHCR	((unsigned long[]){SH_DMAC_BASE + 0x0c, SH_DMAC_BASE + 0x1c, \
-				   SH_DMAC_BASE + 0x2c, SH_DMAC_BASE + 0x3c, \
-				   SH_DMAC_BASE + 0x5c, SH_DMAC_BASE + 0x6c})
+#define SAR ((unsigned long[]){SH_DMAC_BASE + 0x00, SH_DMAC_BASE + 0x10, \
+					SH_DMAC_BASE + 0x20, SH_DMAC_BASE + 0x30, \
+					SH_DMAC_BASE + 0x50, SH_DMAC_BASE + 0x60})

-#define DMAOR	(SH_DMAC_BASE + 0x40)
+#define DAR ((unsigned long[]){SH_DMAC_BASE + 0x04, SH_DMAC_BASE + 0x14, \
+					SH_DMAC_BASE + 0x24, SH_DMAC_BASE + 0x34, \
+					SH_DMAC_BASE + 0x54, SH_DMAC_BASE + 0x64})
+
+#define DMATCR ((unsigned long[]){SH_DMAC_BASE + 0x08, SH_DMAC_BASE + 0x18, \
+					SH_DMAC_BASE + 0x28, SH_DMAC_BASE + 0x38, \
+					SH_DMAC_BASE + 0x58, SH_DMAC_BASE + 0x68})
+
+#define CHCR ((unsigned long[]){SH_DMAC_BASE + 0x0c, SH_DMAC_BASE + 0x1c, \
+					SH_DMAC_BASE + 0x2c, SH_DMAC_BASE + 0x3c, \
+					SH_DMAC_BASE + 0x5c, SH_DMAC_BASE + 0x6c})
+
+#define DMAOR (SH_DMAC_BASE + 0x40)
+
+#define DMASR ((unsigned long[]){SH_DMAC_BASE + 0xFE0, SH_DMAC_BASE + 0xFE0, \
+					SH_DMAC_BASE + 0xFE4, SH_DMAC_BASE + 0xFE4, \
+					SH_DMAC_BASE + 0xFE8, SH_DMAC_BASE + 0xFE8})

 #endif /* __DMA_SH_H */

diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c
index 5e22689..38c3edc 100644
--- a/arch/sh/drivers/dma/dmabrg.c
+++ b/arch/sh/drivers/dma/dmabrg.c
@@ -160,7 +160,7 @@ static int __init dmabrg_init(void)

 #ifdef CONFIG_SH_DMA
 	/* request DMAC channel 0 before anyone else can get it */
-	ret = request_dma(0, "DMAC 0 (DMABRG)");
+	ret = request_dma(0, "DMAC 0 (DMABRG)", NULL, NULL);
 	if (ret < 0)
 		printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n");
 #endif
diff --git a/arch/sh/include/asm/dma.h b/arch/sh/include/asm/dma.h
index beca712..e29fbd2 100644
--- a/arch/sh/include/asm/dma.h
+++ b/arch/sh/include/asm/dma.h
@@ -1,5 +1,5 @@
 /*
- * include/asm-sh/dma.h
+ * arch/sh/include/asm/dma.h
  *
  * Copyright (C) 2003, 2004  Paul Mundt
  *
@@ -13,6 +13,7 @@

 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/sysdev.h>
 #include <cpu/dma.h>
@@ -67,13 +68,16 @@ extern spinlock_t dma_spin_lock;
 struct dma_channel;

 struct dma_ops {
-	int (*request)(struct dma_channel *chan);
-	void (*free)(struct dma_channel *chan);
+	int (*request)(struct dma_channel *chan, irq_handler_t handler,
+						void *data);
+	void (*free)(struct dma_channel *chan, void *data);

 	int (*get_residue)(struct dma_channel *chan);
 	int (*xfer)(struct dma_channel *chan);
 	int (*configure)(struct dma_channel *chan, unsigned long flags);
 	int (*extend)(struct dma_channel *chan, unsigned long op, void *param);
+	void (*start)(struct dma_channel *chan);
+	void (*stop)(struct dma_channel *chan);
 };

 struct dma_channel {
@@ -124,6 +128,21 @@ struct dma_chan_caps {
 /* arch/sh/drivers/dma/dma-api.c */
 extern int dma_xfer(unsigned int chan, unsigned long from,
 		    unsigned long to, size_t size, unsigned int mode);
+/* SAR */
+#define dma_set_sar(val, chan)	ctrl_outl(val, SAR[chan])
+#define dma_get_sar(chan)		ctrl_inl(SAR[chan])
+/* DAR */
+#define dma_set_dar(val, chan)	ctrl_outl(val, DAR[chan])
+#define dma_get_dar(chan)		ctrl_inl(DAR[chan])
+/* DMATCR */
+#define dma_set_dmatcr(val, chan) ctrl_outl(val, DMATCR[chan])
+#define dma_get_dmatcr(chan) ctrl_inl(DMATCR[chan])
+/* CHCR */
+#define dma_set_chcr(val, chan)	ctrl_outl(val, CHCR[chan])
+#define dma_get_chcr(chan)		ctrl_inl(CHCR[chan])
+/* DMASR */
+#define dma_set_dmasr(val, chan)	ctrl_outw(val, DMASR[chan])
+#define dma_get_dmasr(chan)			ctrl_inw(DMASR[chan])

 #define dma_write(chan, from, to, size)	\
 	dma_xfer(chan, from, to, size, DMA_MODE_WRITE)
@@ -135,10 +154,15 @@ extern int dma_xfer(unsigned int chan, unsigned long from,
 #define dma_read_page(chan, from, to)	\
 	dma_read(chan, from, to, PAGE_SIZE)

+extern int dma_start(unsigned int chan);
+extern int dma_stop(unsigned int chan);
+
 extern int request_dma_bycap(const char **dmac, const char **caps,
-			     const char *dev_id);
-extern int request_dma(unsigned int chan, const char *dev_id);
-extern void free_dma(unsigned int chan);
+			const char *dev_id, irq_handler_t handler, void *data);
+extern int dmac_search_free_channel(void);
+extern int request_dma(unsigned int chan, const char *dev_id,
+			irq_handler_t handler, void *data);
+extern void free_dma(unsigned int chan, void *data);
 extern int get_dma_residue(unsigned int chan);
 extern struct dma_info *get_dma_info(unsigned int chan);
 extern struct dma_channel *get_dma_channel(unsigned int chan);
diff --git a/arch/sh/include/cpu-sh4/cpu/dma.h b/arch/sh/include/cpu-sh4/cpu/dma.h
index 235b7cd..1d2bd3b 100644
--- a/arch/sh/include/cpu-sh4/cpu/dma.h
+++ b/arch/sh/include/cpu-sh4/cpu/dma.h
@@ -15,7 +15,14 @@
 #define DMAE_IRQ	38

 #ifdef CONFIG_CPU_SH4A
-#define SH_DMAC_BASE	0xfc808020
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7763) ||\
+	defined(CONFIG_CPU_SUBTYPE_SH7764)
+# define SH_DMAC_BASE  0xff608020
+#else
+/* SH7780/SH7785 */
+# define SH_DMAC_BASE  0xfc808020
+#endif

 #define CHCR_TS_MASK	0x18
 #define CHCR_TS_SHIFT	3
-- 
1.5.6.3


             reply	other threads:[~2008-09-29  9:26 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-09-29  9:26 Nobuhiro Iwamatsu [this message]
  -- strict thread matches above, loose matches on Subject: below --
2008-10-20  4:24 [RFC][PATCH] sh: override DMA interrupt handler to dma-sh driver Paul Mundt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48E09F55.4030406@renesas.com \
    --to=iwamatsu.nobuhiro@renesas.com \
    --cc=linux-sh@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox