Merge branch 'topic/sh' into for-linus

Conflicts:
	drivers/dma/sh/Kconfig
	drivers/dma/sh/shdmac.c

Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
Vinod Koul 2013-09-02 17:42:35 +05:30
commit 265d9c673d
12 changed files with 301 additions and 168 deletions

View File

@ -22,42 +22,51 @@ Optional properties (currently unused):
* DMA controller * DMA controller
Required properties: Required properties:
- compatible: should be "renesas,shdma" - compatible: should be of the form "renesas,shdma-<soc>", where <soc> should
be replaced with the desired SoC model, e.g.
"renesas,shdma-r8a73a4" for the system DMAC on r8a73a4 SoC
Example: Example:
dmac: dma-mux0 { dmac: dma-multiplexer@0 {
compatible = "renesas,shdma-mux"; compatible = "renesas,shdma-mux";
#dma-cells = <1>; #dma-cells = <1>;
dma-channels = <6>; dma-channels = <20>;
dma-requests = <256>; dma-requests = <256>;
reg = <0 0>; /* Needed for AUXDATA */ #address-cells = <2>;
#address-cells = <1>; #size-cells = <2>;
#size-cells = <1>;
ranges; ranges;
dma0: shdma@fe008020 { dma0: dma-controller@e6700020 {
compatible = "renesas,shdma"; compatible = "renesas,shdma-r8a73a4";
reg = <0xfe008020 0x270>, reg = <0 0xe6700020 0 0x89e0>;
<0xfe009000 0xc>;
interrupt-parent = <&gic>; interrupt-parent = <&gic>;
interrupts = <0 34 4 interrupts = <0 220 4
0 28 4 0 200 4
0 29 4 0 201 4
0 30 4 0 202 4
0 31 4 0 203 4
0 32 4 0 204 4
0 33 4>; 0 205 4
0 206 4
0 207 4
0 208 4
0 209 4
0 210 4
0 211 4
0 212 4
0 213 4
0 214 4
0 215 4
0 216 4
0 217 4
0 218 4
0 219 4>;
interrupt-names = "error", interrupt-names = "error",
"ch0", "ch1", "ch2", "ch3", "ch0", "ch1", "ch2", "ch3",
"ch4", "ch5"; "ch4", "ch5", "ch6", "ch7",
}; "ch8", "ch9", "ch10", "ch11",
"ch12", "ch13", "ch14", "ch15",
dma1: shdma@fe018020 { "ch16", "ch17", "ch18", "ch19";
...
};
dma2: shdma@fe028020 {
...
}; };
}; };

View File

@ -28,3 +28,7 @@ config RCAR_HPB_DMAE
depends on SH_DMAE_BASE depends on SH_DMAE_BASE
help help
Enable support for the Renesas R-Car series DMA controllers. Enable support for the Renesas R-Car series DMA controllers.
config SHDMA_R8A73A4
def_bool y
depends on ARCH_R8A73A4 && SH_DMAE != n

View File

@ -1,4 +1,9 @@
obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
obj-$(CONFIG_SH_DMAE) += shdma.o obj-$(CONFIG_SH_DMAE) += shdma.o
shdma-y := shdmac.o
ifeq ($(CONFIG_OF),y)
shdma-$(CONFIG_SHDMA_R8A73A4) += shdma-r8a73a4.o
endif
shdma-objs := $(shdma-y)
obj-$(CONFIG_SUDMAC) += sudmac.o obj-$(CONFIG_SUDMAC) += sudmac.o
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o

View File

@ -0,0 +1,51 @@
/*
* Renesas SuperH DMA Engine support
*
* Copyright (C) 2013 Renesas Electronics, Inc.
*
* This is free software; you can redistribute it and/or modify it under the
* terms of version 2 the GNU General Public License as published by the Free
* Software Foundation.
*/
#ifndef SHDMA_ARM_H
#define SHDMA_ARM_H
#include "shdma.h"
/* Transmit sizes and respective CHCR register values */
enum {
XMIT_SZ_8BIT = 0,
XMIT_SZ_16BIT = 1,
XMIT_SZ_32BIT = 2,
XMIT_SZ_64BIT = 7,
XMIT_SZ_128BIT = 3,
XMIT_SZ_256BIT = 4,
XMIT_SZ_512BIT = 5,
};
/* log2(size / 8) - used to calculate number of transfers */
#define SH_DMAE_TS_SHIFT { \
[XMIT_SZ_8BIT] = 0, \
[XMIT_SZ_16BIT] = 1, \
[XMIT_SZ_32BIT] = 2, \
[XMIT_SZ_64BIT] = 3, \
[XMIT_SZ_128BIT] = 4, \
[XMIT_SZ_256BIT] = 5, \
[XMIT_SZ_512BIT] = 6, \
}
#define TS_LOW_BIT 0x3 /* --xx */
#define TS_HI_BIT 0xc /* xx-- */
#define TS_LOW_SHIFT (3)
#define TS_HI_SHIFT (20 - 2) /* 2 bits for shifted low TS */
#define TS_INDEX2VAL(i) \
((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\
(((i) & TS_HI_BIT) << TS_HI_SHIFT))
#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
#endif

View File

@ -171,7 +171,8 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan)
return NULL; return NULL;
} }
static int shdma_setup_slave(struct shdma_chan *schan, int slave_id) static int shdma_setup_slave(struct shdma_chan *schan, int slave_id,
dma_addr_t slave_addr)
{ {
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops; const struct shdma_ops *ops = sdev->ops;
@ -179,7 +180,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
if (schan->dev->of_node) { if (schan->dev->of_node) {
match = schan->hw_req; match = schan->hw_req;
ret = ops->set_slave(schan, match, true); ret = ops->set_slave(schan, match, slave_addr, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -194,7 +195,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
if (test_and_set_bit(slave_id, shdma_slave_used)) if (test_and_set_bit(slave_id, shdma_slave_used))
return -EBUSY; return -EBUSY;
ret = ops->set_slave(schan, match, false); ret = ops->set_slave(schan, match, slave_addr, false);
if (ret < 0) { if (ret < 0) {
clear_bit(slave_id, shdma_slave_used); clear_bit(slave_id, shdma_slave_used);
return ret; return ret;
@ -236,7 +237,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
if (!schan->dev->of_node && match >= slave_num) if (!schan->dev->of_node && match >= slave_num)
return false; return false;
ret = ops->set_slave(schan, match, true); ret = ops->set_slave(schan, match, 0, true);
if (ret < 0) if (ret < 0)
return false; return false;
@ -259,7 +260,7 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
*/ */
if (slave) { if (slave) {
/* Legacy mode: .private is set in filter */ /* Legacy mode: .private is set in filter */
ret = shdma_setup_slave(schan, slave->slave_id); ret = shdma_setup_slave(schan, slave->slave_id, 0);
if (ret < 0) if (ret < 0)
goto esetslave; goto esetslave;
} else { } else {
@ -680,7 +681,9 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
* channel, while using it... * channel, while using it...
*/ */
config = (struct dma_slave_config *)arg; config = (struct dma_slave_config *)arg;
ret = shdma_setup_slave(schan, config->slave_id); ret = shdma_setup_slave(schan, config->slave_id,
config->direction == DMA_DEV_TO_MEM ?
config->src_addr : config->dst_addr);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; break;
@ -831,8 +834,8 @@ static irqreturn_t chan_irqt(int irq, void *dev)
int shdma_request_irq(struct shdma_chan *schan, int irq, int shdma_request_irq(struct shdma_chan *schan, int irq,
unsigned long flags, const char *name) unsigned long flags, const char *name)
{ {
int ret = request_threaded_irq(irq, chan_irq, chan_irqt, int ret = devm_request_threaded_irq(schan->dev, irq, chan_irq,
flags, name, schan); chan_irqt, flags, name, schan);
schan->irq = ret < 0 ? ret : irq; schan->irq = ret < 0 ? ret : irq;
@ -840,13 +843,6 @@ int shdma_request_irq(struct shdma_chan *schan, int irq,
} }
EXPORT_SYMBOL(shdma_request_irq); EXPORT_SYMBOL(shdma_request_irq);
void shdma_free_irq(struct shdma_chan *schan)
{
if (schan->irq >= 0)
free_irq(schan->irq, schan);
}
EXPORT_SYMBOL(shdma_free_irq);
void shdma_chan_probe(struct shdma_dev *sdev, void shdma_chan_probe(struct shdma_dev *sdev,
struct shdma_chan *schan, int id) struct shdma_chan *schan, int id)
{ {

View File

@ -45,9 +45,6 @@ static int shdma_of_probe(struct platform_device *pdev)
const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev); const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
int ret; int ret;
if (!lookup)
return -EINVAL;
ret = of_dma_controller_register(pdev->dev.of_node, ret = of_dma_controller_register(pdev->dev.of_node,
shdma_of_xlate, pdev); shdma_of_xlate, pdev);
if (ret < 0) if (ret < 0)

View File

@ -0,0 +1,77 @@
/*
* Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
*
* Copyright (C) 2013 Renesas Electronics, Inc.
*
* This is free software; you can redistribute it and/or modify it under the
* terms of version 2 the GNU General Public License as published by the Free
* Software Foundation.
*/
#include <linux/sh_dma.h>
#include "shdma-arm.h"
const unsigned int dma_ts_shift[] = SH_DMAE_TS_SHIFT;
static const struct sh_dmae_slave_config dma_slaves[] = {
{
.chcr = CHCR_TX(XMIT_SZ_32BIT),
.mid_rid = 0xd1, /* MMC0 Tx */
}, {
.chcr = CHCR_RX(XMIT_SZ_32BIT),
.mid_rid = 0xd2, /* MMC0 Rx */
}, {
.chcr = CHCR_TX(XMIT_SZ_32BIT),
.mid_rid = 0xe1, /* MMC1 Tx */
}, {
.chcr = CHCR_RX(XMIT_SZ_32BIT),
.mid_rid = 0xe2, /* MMC1 Rx */
},
};
#define DMAE_CHANNEL(a, b) \
{ \
.offset = (a) - 0x20, \
.dmars = (a) - 0x20 + 0x40, \
.chclr_bit = (b), \
.chclr_offset = 0x80 - 0x20, \
}
static const struct sh_dmae_channel dma_channels[] = {
DMAE_CHANNEL(0x8000, 0),
DMAE_CHANNEL(0x8080, 1),
DMAE_CHANNEL(0x8100, 2),
DMAE_CHANNEL(0x8180, 3),
DMAE_CHANNEL(0x8200, 4),
DMAE_CHANNEL(0x8280, 5),
DMAE_CHANNEL(0x8300, 6),
DMAE_CHANNEL(0x8380, 7),
DMAE_CHANNEL(0x8400, 8),
DMAE_CHANNEL(0x8480, 9),
DMAE_CHANNEL(0x8500, 10),
DMAE_CHANNEL(0x8580, 11),
DMAE_CHANNEL(0x8600, 12),
DMAE_CHANNEL(0x8680, 13),
DMAE_CHANNEL(0x8700, 14),
DMAE_CHANNEL(0x8780, 15),
DMAE_CHANNEL(0x8800, 16),
DMAE_CHANNEL(0x8880, 17),
DMAE_CHANNEL(0x8900, 18),
DMAE_CHANNEL(0x8980, 19),
};
const struct sh_dmae_pdata r8a73a4_dma_pdata = {
.slave = dma_slaves,
.slave_num = ARRAY_SIZE(dma_slaves),
.channel = dma_channels,
.channel_num = ARRAY_SIZE(dma_channels),
.ts_low_shift = TS_LOW_SHIFT,
.ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT,
.ts_high_shift = TS_HI_SHIFT,
.ts_high_mask = TS_HI_BIT << TS_HI_SHIFT,
.ts_shift = dma_ts_shift,
.ts_shift_num = ARRAY_SIZE(dma_ts_shift),
.dmaor_init = DMAOR_DME,
.chclr_present = 1,
.chclr_bitwise = 1,
};

View File

@ -28,18 +28,19 @@ struct sh_dmae_chan {
struct shdma_chan shdma_chan; struct shdma_chan shdma_chan;
const struct sh_dmae_slave_config *config; /* Slave DMA configuration */ const struct sh_dmae_slave_config *config; /* Slave DMA configuration */
int xmit_shift; /* log_2(bytes_per_xfer) */ int xmit_shift; /* log_2(bytes_per_xfer) */
u32 __iomem *base; void __iomem *base;
char dev_id[16]; /* unique name per DMAC of channel */ char dev_id[16]; /* unique name per DMAC of channel */
int pm_error; int pm_error;
dma_addr_t slave_addr;
}; };
struct sh_dmae_device { struct sh_dmae_device {
struct shdma_dev shdma_dev; struct shdma_dev shdma_dev;
struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS]; struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS];
struct sh_dmae_pdata *pdata; const struct sh_dmae_pdata *pdata;
struct list_head node; struct list_head node;
u32 __iomem *chan_reg; void __iomem *chan_reg;
u16 __iomem *dmars; void __iomem *dmars;
unsigned int chcr_offset; unsigned int chcr_offset;
u32 chcr_ie_bit; u32 chcr_ie_bit;
}; };
@ -61,4 +62,11 @@ struct sh_dmae_desc {
#define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\ #define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\
struct sh_dmae_device, shdma_dev.dma_dev) struct sh_dmae_device, shdma_dev.dma_dev)
#ifdef CONFIG_SHDMA_R8A73A4
extern const struct sh_dmae_pdata r8a73a4_dma_pdata;
#define r8a73a4_shdma_devid (&r8a73a4_dma_pdata)
#else
#define r8a73a4_shdma_devid NULL
#endif
#endif /* __DMA_SHDMA_H */ #endif /* __DMA_SHDMA_H */

View File

@ -20,6 +20,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
@ -35,6 +37,15 @@
#include "../dmaengine.h" #include "../dmaengine.h"
#include "shdma.h" #include "shdma.h"
/* DMA register */
#define SAR 0x00
#define DAR 0x04
#define TCR 0x08
#define CHCR 0x0C
#define DMAOR 0x40
#define TEND 0x18 /* USB-DMAC */
#define SH_DMAE_DRV_NAME "sh-dma-engine" #define SH_DMAE_DRV_NAME "sh-dma-engine"
/* Default MEMCPY transfer size = 2^2 = 4 bytes */ /* Default MEMCPY transfer size = 2^2 = 4 bytes */
@ -49,27 +60,37 @@
static DEFINE_SPINLOCK(sh_dmae_lock); static DEFINE_SPINLOCK(sh_dmae_lock);
static LIST_HEAD(sh_dmae_devices); static LIST_HEAD(sh_dmae_devices);
static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data) /*
* Different DMAC implementations provide different ways to clear DMA channels:
* (1) none - no CHCLR registers are available
* (2) one CHCLR register per channel - 0 has to be written to it to clear
* channel buffers
* (3) one CHCLR per several channels - 1 has to be written to the bit,
* corresponding to the specific channel to reset it
*/
static void channel_clear(struct sh_dmae_chan *sh_dc)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_dc); struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
const struct sh_dmae_channel *chan_pdata = shdev->pdata->channel +
sh_dc->shdma_chan.id;
u32 val = shdev->pdata->chclr_bitwise ? 1 << chan_pdata->chclr_bit : 0;
__raw_writel(data, shdev->chan_reg + __raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset);
shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset);
} }
static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
{ {
__raw_writel(data, sh_dc->base + reg / sizeof(u32)); __raw_writel(data, sh_dc->base + reg);
} }
static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg) static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
{ {
return __raw_readl(sh_dc->base + reg / sizeof(u32)); return __raw_readl(sh_dc->base + reg);
} }
static u16 dmaor_read(struct sh_dmae_device *shdev) static u16 dmaor_read(struct sh_dmae_device *shdev)
{ {
u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32); void __iomem *addr = shdev->chan_reg + DMAOR;
if (shdev->pdata->dmaor_is_32bit) if (shdev->pdata->dmaor_is_32bit)
return __raw_readl(addr); return __raw_readl(addr);
@ -79,7 +100,7 @@ static u16 dmaor_read(struct sh_dmae_device *shdev)
static void dmaor_write(struct sh_dmae_device *shdev, u16 data) static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
{ {
u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32); void __iomem *addr = shdev->chan_reg + DMAOR;
if (shdev->pdata->dmaor_is_32bit) if (shdev->pdata->dmaor_is_32bit)
__raw_writel(data, addr); __raw_writel(data, addr);
@ -91,14 +112,14 @@ static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_dc); struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
__raw_writel(data, sh_dc->base + shdev->chcr_offset / sizeof(u32)); __raw_writel(data, sh_dc->base + shdev->chcr_offset);
} }
static u32 chcr_read(struct sh_dmae_chan *sh_dc) static u32 chcr_read(struct sh_dmae_chan *sh_dc)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_dc); struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
return __raw_readl(sh_dc->base + shdev->chcr_offset / sizeof(u32)); return __raw_readl(sh_dc->base + shdev->chcr_offset);
} }
/* /*
@ -133,7 +154,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
for (i = 0; i < shdev->pdata->channel_num; i++) { for (i = 0; i < shdev->pdata->channel_num; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i]; struct sh_dmae_chan *sh_chan = shdev->chan[i];
if (sh_chan) if (sh_chan)
chclr_write(sh_chan, 0); channel_clear(sh_chan);
} }
} }
@ -167,7 +188,7 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr) static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_chan); struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_pdata *pdata = shdev->pdata;
int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) | int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift); ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
@ -180,7 +201,7 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size) static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_chan); struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_pdata *pdata = shdev->pdata;
int i; int i;
for (i = 0; i < pdata->ts_shift_num; i++) for (i = 0; i < pdata->ts_shift_num; i++)
@ -240,9 +261,9 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_chan); struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_pdata *pdata = shdev->pdata;
const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id]; const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id];
u16 __iomem *addr = shdev->dmars; void __iomem *addr = shdev->dmars;
unsigned int shift = chan_pdata->dmars_bit; unsigned int shift = chan_pdata->dmars_bit;
if (dmae_is_busy(sh_chan)) if (dmae_is_busy(sh_chan))
@ -253,8 +274,8 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
/* in the case of a missing DMARS resource use first memory window */ /* in the case of a missing DMARS resource use first memory window */
if (!addr) if (!addr)
addr = (u16 __iomem *)shdev->chan_reg; addr = shdev->chan_reg;
addr += chan_pdata->dmars / sizeof(u16); addr += chan_pdata->dmars;
__raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift), __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
addr); addr);
@ -309,7 +330,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
struct sh_dmae_chan *sh_chan, int match) struct sh_dmae_chan *sh_chan, int match)
{ {
struct sh_dmae_device *shdev = to_sh_dev(sh_chan); struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_pdata *pdata = shdev->pdata;
const struct sh_dmae_slave_config *cfg; const struct sh_dmae_slave_config *cfg;
int i; int i;
@ -323,7 +344,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
} else { } else {
for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
if (cfg->mid_rid == match) { if (cfg->mid_rid == match) {
sh_chan->shdma_chan.slave_id = cfg->slave_id; sh_chan->shdma_chan.slave_id = i;
return cfg; return cfg;
} }
} }
@ -332,7 +353,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
} }
static int sh_dmae_set_slave(struct shdma_chan *schan, static int sh_dmae_set_slave(struct shdma_chan *schan,
int slave_id, bool try) int slave_id, dma_addr_t slave_addr, bool try)
{ {
struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan, struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
shdma_chan); shdma_chan);
@ -340,8 +361,10 @@ static int sh_dmae_set_slave(struct shdma_chan *schan,
if (!cfg) if (!cfg)
return -ENXIO; return -ENXIO;
if (!try) if (!try) {
sh_chan->config = cfg; sh_chan->config = cfg;
sh_chan->slave_addr = slave_addr ? : cfg->addr;
}
return 0; return 0;
} }
@ -505,7 +528,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
struct shdma_chan *schan; struct shdma_chan *schan;
int err; int err;
sh_chan = kzalloc(sizeof(struct sh_dmae_chan), GFP_KERNEL); sh_chan = devm_kzalloc(sdev->dma_dev.dev, sizeof(struct sh_dmae_chan),
GFP_KERNEL);
if (!sh_chan) { if (!sh_chan) {
dev_err(sdev->dma_dev.dev, dev_err(sdev->dma_dev.dev,
"No free memory for allocating dma channels!\n"); "No free memory for allocating dma channels!\n");
@ -517,7 +541,7 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
shdma_chan_probe(sdev, schan, id); shdma_chan_probe(sdev, schan, id);
sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32); sh_chan->base = shdev->chan_reg + chan_pdata->offset;
/* set up channel irq */ /* set up channel irq */
if (pdev->id >= 0) if (pdev->id >= 0)
@ -541,7 +565,6 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
err_no_irq: err_no_irq:
/* remove from dmaengine device node */ /* remove from dmaengine device node */
shdma_chan_remove(schan); shdma_chan_remove(schan);
kfree(sh_chan);
return err; return err;
} }
@ -552,14 +575,9 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
int i; int i;
shdma_for_each_chan(schan, &shdev->shdma_dev, i) { shdma_for_each_chan(schan, &shdev->shdma_dev, i) {
struct sh_dmae_chan *sh_chan = container_of(schan,
struct sh_dmae_chan, shdma_chan);
BUG_ON(!schan); BUG_ON(!schan);
shdma_free_irq(&sh_chan->shdma_chan);
shdma_chan_remove(schan); shdma_chan_remove(schan);
kfree(sh_chan);
} }
dma_dev->chancnt = 0; dma_dev->chancnt = 0;
} }
@ -636,7 +654,7 @@ static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan)
* This is an exclusive slave DMA operation, may only be called after a * This is an exclusive slave DMA operation, may only be called after a
* successful slave configuration. * successful slave configuration.
*/ */
return sh_chan->config->addr; return sh_chan->slave_addr;
} }
static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i) static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i)
@ -658,9 +676,15 @@ static const struct shdma_ops sh_dmae_shdma_ops = {
.get_partial = sh_dmae_get_partial, .get_partial = sh_dmae_get_partial,
}; };
static const struct of_device_id sh_dmae_of_match[] = {
{.compatible = "renesas,shdma-r8a73a4", .data = r8a73a4_shdma_devid,},
{}
};
MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
static int sh_dmae_probe(struct platform_device *pdev) static int sh_dmae_probe(struct platform_device *pdev)
{ {
struct sh_dmae_pdata *pdata = dev_get_platdata(&pdev->dev); const struct sh_dmae_pdata *pdata;
unsigned long irqflags = IRQF_DISABLED, unsigned long irqflags = IRQF_DISABLED,
chan_flag[SH_DMAE_MAX_CHANNELS] = {}; chan_flag[SH_DMAE_MAX_CHANNELS] = {};
int errirq, chan_irq[SH_DMAE_MAX_CHANNELS]; int errirq, chan_irq[SH_DMAE_MAX_CHANNELS];
@ -669,6 +693,11 @@ static int sh_dmae_probe(struct platform_device *pdev)
struct dma_device *dma_dev; struct dma_device *dma_dev;
struct resource *chan, *dmars, *errirq_res, *chanirq_res; struct resource *chan, *dmars, *errirq_res, *chanirq_res;
if (pdev->dev.of_node)
pdata = of_match_device(sh_dmae_of_match, &pdev->dev)->data;
else
pdata = dev_get_platdata(&pdev->dev);
/* get platform data */ /* get platform data */
if (!pdata || !pdata->channel_num) if (!pdata || !pdata->channel_num)
return -ENODEV; return -ENODEV;
@ -696,33 +725,22 @@ static int sh_dmae_probe(struct platform_device *pdev)
if (!chan || !errirq_res) if (!chan || !errirq_res)
return -ENODEV; return -ENODEV;
if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) { shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
dev_err(&pdev->dev, "DMAC register region already claimed\n"); GFP_KERNEL);
return -EBUSY;
}
if (dmars && !request_mem_region(dmars->start, resource_size(dmars), pdev->name)) {
dev_err(&pdev->dev, "DMAC DMARS region already claimed\n");
err = -EBUSY;
goto ermrdmars;
}
err = -ENOMEM;
shdev = kzalloc(sizeof(struct sh_dmae_device), GFP_KERNEL);
if (!shdev) { if (!shdev) {
dev_err(&pdev->dev, "Not enough memory\n"); dev_err(&pdev->dev, "Not enough memory\n");
goto ealloc; return -ENOMEM;
} }
dma_dev = &shdev->shdma_dev.dma_dev; dma_dev = &shdev->shdma_dev.dma_dev;
shdev->chan_reg = ioremap(chan->start, resource_size(chan)); shdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
if (!shdev->chan_reg) if (IS_ERR(shdev->chan_reg))
goto emapchan; return PTR_ERR(shdev->chan_reg);
if (dmars) { if (dmars) {
shdev->dmars = ioremap(dmars->start, resource_size(dmars)); shdev->dmars = devm_ioremap_resource(&pdev->dev, dmars);
if (!shdev->dmars) if (IS_ERR(shdev->dmars))
goto emapdmars; return PTR_ERR(shdev->dmars);
} }
if (!pdata->slave_only) if (!pdata->slave_only)
@ -783,7 +801,7 @@ static int sh_dmae_probe(struct platform_device *pdev)
errirq = errirq_res->start; errirq = errirq_res->start;
err = request_irq(errirq, sh_dmae_err, irqflags, err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags,
"DMAC Address Error", shdev); "DMAC Address Error", shdev);
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
@ -862,7 +880,6 @@ chan_probe_err:
sh_dmae_chan_remove(shdev); sh_dmae_chan_remove(shdev);
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
free_irq(errirq, shdev);
eirq_err: eirq_err:
#endif #endif
rst_err: rst_err:
@ -873,21 +890,9 @@ rst_err:
pm_runtime_put(&pdev->dev); pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
shdma_cleanup(&shdev->shdma_dev); shdma_cleanup(&shdev->shdma_dev);
eshdma: eshdma:
if (dmars)
iounmap(shdev->dmars);
emapdmars:
iounmap(shdev->chan_reg);
synchronize_rcu(); synchronize_rcu();
emapchan:
kfree(shdev);
ealloc:
if (dmars)
release_mem_region(dmars->start, resource_size(dmars));
ermrdmars:
release_mem_region(chan->start, resource_size(chan));
return err; return err;
} }
@ -896,14 +901,9 @@ static int sh_dmae_remove(struct platform_device *pdev)
{ {
struct sh_dmae_device *shdev = platform_get_drvdata(pdev); struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev; struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
struct resource *res;
int errirq = platform_get_irq(pdev, 0);
dma_async_device_unregister(dma_dev); dma_async_device_unregister(dma_dev);
if (errirq > 0)
free_irq(errirq, shdev);
spin_lock_irq(&sh_dmae_lock); spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node); list_del_rcu(&shdev->node);
spin_unlock_irq(&sh_dmae_lock); spin_unlock_irq(&sh_dmae_lock);
@ -913,31 +913,11 @@ static int sh_dmae_remove(struct platform_device *pdev)
sh_dmae_chan_remove(shdev); sh_dmae_chan_remove(shdev);
shdma_cleanup(&shdev->shdma_dev); shdma_cleanup(&shdev->shdma_dev);
if (shdev->dmars)
iounmap(shdev->dmars);
iounmap(shdev->chan_reg);
platform_set_drvdata(pdev, NULL);
synchronize_rcu(); synchronize_rcu();
kfree(shdev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res)
release_mem_region(res->start, resource_size(res));
return 0; return 0;
} }
static const struct of_device_id sh_dmae_of_match[] = {
{ .compatible = "renesas,shdma", },
{ }
};
MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
static struct platform_driver sh_dmae_driver = { static struct platform_driver sh_dmae_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -150,7 +150,8 @@ static const struct sudmac_slave_config *sudmac_find_slave(
return NULL; return NULL;
} }
static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, bool try) static int sudmac_set_slave(struct shdma_chan *schan, int slave_id,
dma_addr_t slave_addr, bool try)
{ {
struct sudmac_chan *sc = to_chan(schan); struct sudmac_chan *sc = to_chan(schan);
const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id); const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id);
@ -298,11 +299,8 @@ static void sudmac_chan_remove(struct sudmac_device *su_dev)
int i; int i;
shdma_for_each_chan(schan, &su_dev->shdma_dev, i) { shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
struct sudmac_chan *sc = to_chan(schan);
BUG_ON(!schan); BUG_ON(!schan);
shdma_free_irq(&sc->shdma_chan);
shdma_chan_remove(schan); shdma_chan_remove(schan);
} }
dma_dev->chancnt = 0; dma_dev->chancnt = 0;
@ -393,7 +391,6 @@ static int sudmac_probe(struct platform_device *pdev)
chan_probe_err: chan_probe_err:
sudmac_chan_remove(su_dev); sudmac_chan_remove(su_dev);
platform_set_drvdata(pdev, NULL);
shdma_cleanup(&su_dev->shdma_dev); shdma_cleanup(&su_dev->shdma_dev);
return err; return err;
@ -407,7 +404,6 @@ static int sudmac_remove(struct platform_device *pdev)
dma_async_device_unregister(dma_dev); dma_async_device_unregister(dma_dev);
sudmac_chan_remove(su_dev); sudmac_chan_remove(su_dev);
shdma_cleanup(&su_dev->shdma_dev); shdma_cleanup(&su_dev->shdma_dev);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }

View File

@ -33,13 +33,44 @@ struct sh_dmae_slave_config {
char mid_rid; char mid_rid;
}; };
/**
* struct sh_dmae_channel - DMAC channel platform data
* @offset: register offset within the main IOMEM resource
* @dmars: channel DMARS register offset
* @chclr_offset: channel CHCLR register offset
* @dmars_bit: channel DMARS field offset within the register
* @chclr_bit: bit position, to be set to reset the channel
*/
struct sh_dmae_channel { struct sh_dmae_channel {
unsigned int offset; unsigned int offset;
unsigned int dmars; unsigned int dmars;
unsigned int dmars_bit;
unsigned int chclr_offset; unsigned int chclr_offset;
unsigned char dmars_bit;
unsigned char chclr_bit;
}; };
/**
* struct sh_dmae_pdata - DMAC platform data
* @slave: array of slaves
* @slave_num: number of slaves in the above array
* @channel: array of DMA channels
* @channel_num: number of channels in the above array
* @ts_low_shift: shift of the low part of the TS field
* @ts_low_mask: low TS field mask
* @ts_high_shift: additional shift of the high part of the TS field
* @ts_high_mask: high TS field mask
* @ts_shift: array of Transfer Size shifts, indexed by TS value
* @ts_shift_num: number of shifts in the above array
* @dmaor_init: DMAOR initialisation value
* @chcr_offset: CHCR address offset
* @chcr_ie_bit: CHCR Interrupt Enable bit
* @dmaor_is_32bit: DMAOR is a 32-bit register
* @needs_tend_set: the TEND register has to be set
* @no_dmars: DMAC has no DMARS registers
* @chclr_present: DMAC has one or several CHCLR registers
* @chclr_bitwise: channel CHCLR registers are bitwise
* @slave_only: DMAC cannot be used for MEMCPY
*/
struct sh_dmae_pdata { struct sh_dmae_pdata {
const struct sh_dmae_slave_config *slave; const struct sh_dmae_slave_config *slave;
int slave_num; int slave_num;
@ -59,42 +90,22 @@ struct sh_dmae_pdata {
unsigned int needs_tend_set:1; unsigned int needs_tend_set:1;
unsigned int no_dmars:1; unsigned int no_dmars:1;
unsigned int chclr_present:1; unsigned int chclr_present:1;
unsigned int chclr_bitwise:1;
unsigned int slave_only:1; unsigned int slave_only:1;
}; };
/* DMA register */
#define SAR 0x00
#define DAR 0x04
#define TCR 0x08
#define CHCR 0x0C
#define DMAOR 0x40
#define TEND 0x18 /* USB-DMAC */
/* DMAOR definitions */ /* DMAOR definitions */
#define DMAOR_AE 0x00000004 #define DMAOR_AE 0x00000004
#define DMAOR_NMIF 0x00000002 #define DMAOR_NMIF 0x00000002
#define DMAOR_DME 0x00000001 #define DMAOR_DME 0x00000001
/* Definitions for the SuperH DMAC */ /* Definitions for the SuperH DMAC */
#define REQ_L 0x00000000
#define REQ_E 0x00080000
#define RACK_H 0x00000000
#define RACK_L 0x00040000
#define ACK_R 0x00000000
#define ACK_W 0x00020000
#define ACK_H 0x00000000
#define ACK_L 0x00010000
#define DM_INC 0x00004000 #define DM_INC 0x00004000
#define DM_DEC 0x00008000 #define DM_DEC 0x00008000
#define DM_FIX 0x0000c000 #define DM_FIX 0x0000c000
#define SM_INC 0x00001000 #define SM_INC 0x00001000
#define SM_DEC 0x00002000 #define SM_DEC 0x00002000
#define SM_FIX 0x00003000 #define SM_FIX 0x00003000
#define RS_IN 0x00000200
#define RS_OUT 0x00000300
#define TS_BLK 0x00000040
#define TM_BUR 0x00000020
#define CHCR_DE 0x00000001 #define CHCR_DE 0x00000001
#define CHCR_TE 0x00000002 #define CHCR_TE 0x00000002
#define CHCR_IE 0x00000004 #define CHCR_IE 0x00000004

View File

@ -96,7 +96,7 @@ struct shdma_ops {
dma_addr_t (*slave_addr)(struct shdma_chan *); dma_addr_t (*slave_addr)(struct shdma_chan *);
int (*desc_setup)(struct shdma_chan *, struct shdma_desc *, int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
dma_addr_t, dma_addr_t, size_t *); dma_addr_t, dma_addr_t, size_t *);
int (*set_slave)(struct shdma_chan *, int, bool); int (*set_slave)(struct shdma_chan *, int, dma_addr_t, bool);
void (*setup_xfer)(struct shdma_chan *, int); void (*setup_xfer)(struct shdma_chan *, int);
void (*start_xfer)(struct shdma_chan *, struct shdma_desc *); void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
struct shdma_desc *(*embedded_desc)(void *, int); struct shdma_desc *(*embedded_desc)(void *, int);
@ -116,7 +116,6 @@ struct shdma_dev {
int shdma_request_irq(struct shdma_chan *, int, int shdma_request_irq(struct shdma_chan *, int,
unsigned long, const char *); unsigned long, const char *);
void shdma_free_irq(struct shdma_chan *);
bool shdma_reset(struct shdma_dev *sdev); bool shdma_reset(struct shdma_dev *sdev);
void shdma_chan_probe(struct shdma_dev *sdev, void shdma_chan_probe(struct shdma_dev *sdev,
struct shdma_chan *schan, int id); struct shdma_chan *schan, int id);