All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Shimoda, Yoshihiro" <yoshihiro.shimoda.uh@renesas.com>
To: linux-sh@vger.kernel.org
Subject: [PATCH v3 3/3] dmaengine: shdma: add support for SUDMAC
Date: Tue, 10 Jan 2012 06:38:20 +0000	[thread overview]
Message-ID: <4F0BDCDC.2010907@renesas.com> (raw)

The SH7757's USB module has SUDMAC. The SUDMAC's registers are imcompatible
with SH DMAC. However, since the SUDMAC is a very simple module, we can
reuse the shdma driver for SUDMAC by a few modification.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 about v3:
  - No change

 drivers/dma/shdma.c    |  102 +++++++++++++++++++++++++++++++++++++++++++-----
 include/linux/sh_dma.h |   46 +++++++++++++++++++++
 2 files changed, 138 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 4e0ddd6..4ca8921 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -58,6 +58,11 @@ static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)];

 static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all);

+static int sh_dmae_is_sudmac(struct sh_dmae_device *shdev)
+{
+	return shdev->pdata->sudmac;
+}
+
 static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
 {
 	__raw_writel(data, sh_dc->base + reg / sizeof(u32));
@@ -68,6 +73,39 @@ static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
 	return __raw_readl(sh_dc->base + reg / sizeof(u32));
 }

+static void sh_dmae_sudmac_chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
+{
+	struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+	if (!(data & CHCR_TE))	/* clear interrupt status only */
+		sh_dmae_writel(sh_dc, CH0ENDC, DINTSTSCLR);
+
+	if (data & shdev->chcr_ie_bit)
+		sh_dmae_writel(sh_dc, CH0ENDE, DINTCTRL);
+	else
+		sh_dmae_writel(sh_dc, 0, DINTCTRL);
+
+	if (data & CHCR_DE)
+		sh_dmae_writel(sh_dc, DEN, CH0DEN);
+	else
+		sh_dmae_writel(sh_dc, 0, CH0DEN);
+}
+
+static u32 sh_dmae_sudmac_chcr_read(struct sh_dmae_chan *sh_dc)
+{
+	struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+	u32 chcr = 0;
+
+	if (sh_dmae_readl(sh_dc, DINTSTS) & CH0ENDS)
+		chcr |= CHCR_TE;
+	if (sh_dmae_readl(sh_dc, DINTCTRL) & CH0ENDE)
+		chcr |= shdev->chcr_ie_bit;
+	if (sh_dmae_readl(sh_dc, CH0DEN) & DEN)
+		chcr |= CHCR_DE;
+
+	return chcr;
+}
+
 static u16 dmaor_read(struct sh_dmae_device *shdev)
 {
 	u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
@@ -92,14 +130,20 @@ static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
 {
 	struct sh_dmae_device *shdev = to_sh_dev(sh_dc);

-	sh_dmae_writel(sh_dc, data, shdev->chcr_offset);
+	if (sh_dmae_is_sudmac(shdev))
+		sh_dmae_sudmac_chcr_write(sh_dc, data);
+	else
+		sh_dmae_writel(sh_dc, data, shdev->chcr_offset);
 }

 static u32 chcr_read(struct sh_dmae_chan *sh_dc)
 {
 	struct sh_dmae_device *shdev = to_sh_dev(sh_dc);

-	return sh_dmae_readl(sh_dc, shdev->chcr_offset);
+	if (sh_dmae_is_sudmac(shdev))
+		return sh_dmae_sudmac_chcr_read(sh_dc);
+	else
+		return sh_dmae_readl(sh_dc, shdev->chcr_offset);
 }

 /*
@@ -112,6 +156,9 @@ static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
 	unsigned short dmaor;
 	unsigned long flags;

+	if (sh_dmae_is_sudmac(shdev))
+		return;
+
 	spin_lock_irqsave(&sh_dmae_lock, flags);

 	dmaor = dmaor_read(shdev);
@@ -125,6 +172,9 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
 	unsigned short dmaor;
 	unsigned long flags;

+	if (sh_dmae_is_sudmac(shdev))
+		return 0;
+
 	spin_lock_irqsave(&sh_dmae_lock, flags);

 	dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
@@ -159,6 +209,9 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
 	int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
 		((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);

+	if (sh_dmae_is_sudmac(shdev))
+		return 0;
+
 	if (cnt >= pdata->ts_shift_num)
 		cnt = 0;

@@ -171,6 +224,9 @@ static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
 	struct sh_dmae_pdata *pdata = shdev->pdata;
 	int i;

+	if (sh_dmae_is_sudmac(shdev))
+		return 0;
+
 	for (i = 0; i < pdata->ts_shift_num; i++)
 		if (pdata->ts_shift[i] = l2size)
 			break;
@@ -184,9 +240,17 @@ static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)

 static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw)
 {
-	sh_dmae_writel(sh_chan, hw->sar, SAR);
-	sh_dmae_writel(sh_chan, hw->dar, DAR);
-	sh_dmae_writel(sh_chan, hw->tcr >> sh_chan->xmit_shift, TCR);
+	struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+
+	if (sh_dmae_is_sudmac(shdev)) {
+		sh_dmae_writel(sh_chan, LBA_WAIT | RCVENDM, CH0CFG);
+		sh_dmae_writel(sh_chan, hw->sar, CH0BA);
+		sh_dmae_writel(sh_chan, hw->tcr, CH0BBC);
+	} else {
+		sh_dmae_writel(sh_chan, hw->sar, SAR);
+		sh_dmae_writel(sh_chan, hw->dar, DAR);
+		sh_dmae_writel(sh_chan, hw->tcr >> sh_chan->xmit_shift, TCR);
+	}
 }

 static void dmae_start(struct sh_dmae_chan *sh_chan)
@@ -493,6 +557,7 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan,
 	unsigned long flags, dma_addr_t *dest, dma_addr_t *src, size_t *len,
 	struct sh_desc **first, enum dma_data_direction direction)
 {
+	struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
 	struct sh_desc *new;
 	size_t copy_size;

@@ -508,7 +573,14 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan,

 	copy_size = min(*len, (size_t)SH_DMA_TCR_MAX + 1);

-	new->hw.sar = *src;
+	/*
+	 * SUDMAC has a CHnBA register only. So, the driver uses "hw.sar"
+	 * even if transfer direction is DMA_FROM_DEVICE.
+	 */
+	if (sh_dmae_is_sudmac(shdev) && direction = DMA_FROM_DEVICE)
+		new->hw.sar = *dest;
+	else
+		new->hw.sar = *src;
 	new->hw.dar = *dest;
 	new->hw.tcr = copy_size;

@@ -701,8 +773,10 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		/* Record partial transfer */
 		struct sh_desc *desc = list_entry(sh_chan->ld_queue.next,
 						  struct sh_desc, node);
-		desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
-			sh_chan->xmit_shift;
+		struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+		if (!sh_dmae_is_sudmac(shdev))
+			desc->partial = (desc->hw.tcr - sh_dmae_readl(sh_chan,
+						TCR)) << sh_chan->xmit_shift;
 	}
 	spin_unlock_irqrestore(&sh_chan->desc_lock, flags);

@@ -989,9 +1063,17 @@ static irqreturn_t sh_dmae_err(int irq, void *data)
 static void dmae_do_tasklet(unsigned long data)
 {
 	struct sh_dmae_chan *sh_chan = (struct sh_dmae_chan *)data;
+	struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
 	struct sh_desc *desc;
-	u32 sar_buf = sh_dmae_readl(sh_chan, SAR);
-	u32 dar_buf = sh_dmae_readl(sh_chan, DAR);
+	u32 sar_buf, dar_buf;
+
+	if (sh_dmae_is_sudmac(shdev)) {
+		sar_buf = sh_dmae_readl(sh_chan, CH0CA);
+		dar_buf = sh_dmae_readl(sh_chan, CH0CA);
+	} else {
+		sar_buf = sh_dmae_readl(sh_chan, SAR);
+		dar_buf = sh_dmae_readl(sh_chan, DAR);
+	}

 	spin_lock_irq(&sh_chan->desc_lock);
 	list_for_each_entry(desc, &sh_chan->ld_queue, node) {
diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h
index cb2dd11..9997445 100644
--- a/include/linux/sh_dma.h
+++ b/include/linux/sh_dma.h
@@ -68,6 +68,7 @@ struct sh_dmae_pdata {
 	unsigned int dmaor_is_32bit:1;
 	unsigned int needs_tend_set:1;
 	unsigned int no_dmars:1;
+	unsigned int sudmac:1;
 };

 /* DMA register */
@@ -107,4 +108,49 @@ struct sh_dmae_pdata {
 #define CHCR_TE	0x00000002
 #define CHCR_IE	0x00000004

+/* SUDMAC register */
+#define CH0CFG		0x00
+#define CH1CFG		0x04
+#define CH0BA		0x10
+#define CH1BA		0x14
+#define CH0BBC		0x18
+#define CH1BBC		0x1C
+#define CH0CA		0x20
+#define CH1CA		0x24
+#define CH0CBC		0x28
+#define CH1CBC		0x2C
+#define CH0DEN		0x30
+#define CH1DEN		0x34
+#define DSTSCLR		0x38
+#define DBUFCTRL	0x3C
+#define DINTCTRL	0x40
+#define DINTSTS		0x44
+#define DINTSTSCLR	0x48
+#define CH0SHCTRL	0x50
+#define CH1SHCTRL	0x54
+
+/* Definitions for the SUDMAC */
+#define SENDBUFM	0x1000 /* b12: Transmit Buffer Mode */
+#define RCVENDM		0x0100 /* b8: Receive Data Transfer End Mode */
+#define LBA_WAIT	0x0030 /* b5-4: Local Bus Access Wait */
+#define DEN		0x0001 /* b0: DMA Transfer Enable */
+#define CH1STCLR	0x0002 /* b1: Ch1 DMA Status Clear */
+#define CH0STCLR	0x0001 /* b0: Ch0 DMA Status Clear */
+#define CH1BUFW		0x0200 /* b9: Ch1 DMA Buffer Data Transfer Enable */
+#define CH0BUFW		0x0100 /* b8: Ch0 DMA Buffer Data Transfer Enable */
+#define CH1BUFS		0x0002 /* b1: Ch1 DMA Buffer Data Status */
+#define CH0BUFS		0x0001 /* b0: Ch0 DMA Buffer Data Status */
+#define CH1ERRE		0x0200 /* b9: Ch1 SHwy Res Err Detect Int Enable */
+#define CH0ERRE		0x0100 /* b8: Ch0 SHwy Res Err Detect Int Enable */
+#define CH1ENDE		0x0002 /* b1: Ch1 DMA Transfer End Int Enable */
+#define CH0ENDE		0x0001 /* b0: Ch0 DMA Transfer End Int Enable */
+#define CH1ERRS		0x0200 /* b9: Ch1 SHwy Res Err Detect Int Status */
+#define CH0ERRS		0x0100 /* b8: Ch0 SHwy Res Err Detect Int Status */
+#define CH1ENDS		0x0002 /* b1: Ch1 DMA Transfer End Int Status */
+#define CH0ENDS		0x0001 /* b0: Ch0 DMA Transfer End Int Status */
+#define CH1ERRC		0x0200 /* b9: Ch1 SHwy Res Err Detect Int Stat Clear */
+#define CH0ERRC		0x0100 /* b8: Ch0 SHwy Res Err Detect Int Stat Clear */
+#define CH1ENDC		0x0002 /* b1: Ch1 DMA Transfer End Int Stat Clear */
+#define CH0ENDC		0x0001 /* b0: Ch0 DMA Transfer End Int Stat Clear */
+
 #endif
-- 
1.7.1

                 reply	other threads:[~2012-01-10  6:38 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=4F0BDCDC.2010907@renesas.com \
    --to=yoshihiro.shimoda.uh@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.