From: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
To: linux-sh@vger.kernel.org
Subject: Re: about dma-sh driver
Date: Wed, 24 Sep 2008 06:36:18 +0000 [thread overview]
Message-ID: <48D9DFE2.5060708@renesas.com> (raw)
In-Reply-To: <29ab51dc0809232129j2a54662bg1e5ac50161f6cc94@mail.gmail.com>
Hi, Paul.
Thank you for your comments.
Paul Mundt wrote:
> On Wed, Sep 24, 2008 at 01:29:56PM +0900, Nobuhiro Iwamatsu wrote:
>> I'm making driver who used dma-sh.
>> I use a dma-sh driver and want to use another interrupt handler.
>> I want to use request, get_residue and other dma_ops functions
>> and change only dma_tei function.
>>
>> Dma-sh has a function for IRQ interrupts in dma-sh driver.
>> For an IRQ interrupt, we cannot register another interrupt handler.
>>
>> Is this right?
>>
>> I think about three suggestion.
>>
>> 1. Add interrupt handler override function to dma-sh and dma-api.
>> I wrote quick hack this suggestion.
>>
>> 2. Create SuperH driver of dma engine and shift dma engine.
>> I hear that dma-sh shifts to dma-engine.
>> But I don't know schedule about dma engine.
>>
>> 3. Do both 1 and 2 in parallelism.
>>
> #3 is probably the easiest. #1 shouldn't take more than 10 minutes to
> hack together, and if you're going to have in-tree stuff making use of
> that, it doesn't make any sense to hold that off while the dmaengine work
> is happening. We can easily accomodate #1 in 2.6.28.
I attached quick hack patch.
I expanded request_dma function, add interrupt handler and data arguments.
Other idea, I make a new function without adding an argument to request_dma(),
and there is a function to do override by this function.
Which will be good?
> #2 is on my todo list, but it will likely be at least 2.6.29 or 2.6.30
> before I even start looking at it. If you want to start on it before
> that, please do. :-)
OK, I'm interesting in this system.
I will start this work , if I have time.
Thank you!
Best regards,
Nobuhiro
---
sh: Add new DMA function
Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@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, ®istered_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
prev parent reply other threads:[~2008-09-24 6:36 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-24 4:29 about dma-sh driver Nobuhiro Iwamatsu
2008-09-24 4:54 ` Paul Mundt
2008-09-24 6:36 ` Nobuhiro Iwamatsu [this message]
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=48D9DFE2.5060708@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 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.