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:
Коммит
265d9c673d
|
@ -22,42 +22,51 @@ Optional properties (currently unused):
|
|||
* DMA controller
|
||||
|
||||
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:
|
||||
dmac: dma-mux0 {
|
||||
dmac: dma-multiplexer@0 {
|
||||
compatible = "renesas,shdma-mux";
|
||||
#dma-cells = <1>;
|
||||
dma-channels = <6>;
|
||||
dma-channels = <20>;
|
||||
dma-requests = <256>;
|
||||
reg = <0 0>; /* Needed for AUXDATA */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
dma0: shdma@fe008020 {
|
||||
compatible = "renesas,shdma";
|
||||
reg = <0xfe008020 0x270>,
|
||||
<0xfe009000 0xc>;
|
||||
dma0: dma-controller@e6700020 {
|
||||
compatible = "renesas,shdma-r8a73a4";
|
||||
reg = <0 0xe6700020 0 0x89e0>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 34 4
|
||||
0 28 4
|
||||
0 29 4
|
||||
0 30 4
|
||||
0 31 4
|
||||
0 32 4
|
||||
0 33 4>;
|
||||
interrupts = <0 220 4
|
||||
0 200 4
|
||||
0 201 4
|
||||
0 202 4
|
||||
0 203 4
|
||||
0 204 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",
|
||||
"ch0", "ch1", "ch2", "ch3",
|
||||
"ch4", "ch5";
|
||||
};
|
||||
|
||||
dma1: shdma@fe018020 {
|
||||
...
|
||||
};
|
||||
|
||||
dma2: shdma@fe028020 {
|
||||
...
|
||||
"ch4", "ch5", "ch6", "ch7",
|
||||
"ch8", "ch9", "ch10", "ch11",
|
||||
"ch12", "ch13", "ch14", "ch15",
|
||||
"ch16", "ch17", "ch18", "ch19";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -28,3 +28,7 @@ config RCAR_HPB_DMAE
|
|||
depends on SH_DMAE_BASE
|
||||
help
|
||||
Enable support for the Renesas R-Car series DMA controllers.
|
||||
|
||||
config SHDMA_R8A73A4
|
||||
def_bool y
|
||||
depends on ARCH_R8A73A4 && SH_DMAE != n
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.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_RCAR_HPB_DMAE) += rcar-hpbdma.o
|
||||
|
|
|
@ -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
|
|
@ -171,7 +171,8 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan)
|
|||
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);
|
||||
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) {
|
||||
match = schan->hw_req;
|
||||
ret = ops->set_slave(schan, match, true);
|
||||
ret = ops->set_slave(schan, match, slave_addr, true);
|
||||
if (ret < 0)
|
||||
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))
|
||||
return -EBUSY;
|
||||
|
||||
ret = ops->set_slave(schan, match, false);
|
||||
ret = ops->set_slave(schan, match, slave_addr, false);
|
||||
if (ret < 0) {
|
||||
clear_bit(slave_id, shdma_slave_used);
|
||||
return ret;
|
||||
|
@ -236,7 +237,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
|
|||
if (!schan->dev->of_node && match >= slave_num)
|
||||
return false;
|
||||
|
||||
ret = ops->set_slave(schan, match, true);
|
||||
ret = ops->set_slave(schan, match, 0, true);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
|
@ -259,7 +260,7 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
|
|||
*/
|
||||
if (slave) {
|
||||
/* 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)
|
||||
goto esetslave;
|
||||
} else {
|
||||
|
@ -680,7 +681,9 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
|||
* channel, while using it...
|
||||
*/
|
||||
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)
|
||||
return ret;
|
||||
break;
|
||||
|
@ -831,8 +834,8 @@ static irqreturn_t chan_irqt(int irq, void *dev)
|
|||
int shdma_request_irq(struct shdma_chan *schan, int irq,
|
||||
unsigned long flags, const char *name)
|
||||
{
|
||||
int ret = request_threaded_irq(irq, chan_irq, chan_irqt,
|
||||
flags, name, schan);
|
||||
int ret = devm_request_threaded_irq(schan->dev, irq, chan_irq,
|
||||
chan_irqt, flags, name, schan);
|
||||
|
||||
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);
|
||||
|
||||
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,
|
||||
struct shdma_chan *schan, int id)
|
||||
{
|
||||
|
|
|
@ -45,9 +45,6 @@ static int shdma_of_probe(struct platform_device *pdev)
|
|||
const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
|
||||
int ret;
|
||||
|
||||
if (!lookup)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_dma_controller_register(pdev->dev.of_node,
|
||||
shdma_of_xlate, pdev);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -28,18 +28,19 @@ struct sh_dmae_chan {
|
|||
struct shdma_chan shdma_chan;
|
||||
const struct sh_dmae_slave_config *config; /* Slave DMA configuration */
|
||||
int xmit_shift; /* log_2(bytes_per_xfer) */
|
||||
u32 __iomem *base;
|
||||
void __iomem *base;
|
||||
char dev_id[16]; /* unique name per DMAC of channel */
|
||||
int pm_error;
|
||||
dma_addr_t slave_addr;
|
||||
};
|
||||
|
||||
struct sh_dmae_device {
|
||||
struct shdma_dev shdma_dev;
|
||||
struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS];
|
||||
struct sh_dmae_pdata *pdata;
|
||||
const struct sh_dmae_pdata *pdata;
|
||||
struct list_head node;
|
||||
u32 __iomem *chan_reg;
|
||||
u16 __iomem *dmars;
|
||||
void __iomem *chan_reg;
|
||||
void __iomem *dmars;
|
||||
unsigned int chcr_offset;
|
||||
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,\
|
||||
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 */
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
@ -35,6 +37,15 @@
|
|||
#include "../dmaengine.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"
|
||||
|
||||
/* Default MEMCPY transfer size = 2^2 = 4 bytes */
|
||||
|
@ -49,27 +60,37 @@
|
|||
static DEFINE_SPINLOCK(sh_dmae_lock);
|
||||
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);
|
||||
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 +
|
||||
shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset);
|
||||
__raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
|
||||
void __iomem *addr = shdev->chan_reg + DMAOR;
|
||||
|
||||
if (shdev->pdata->dmaor_is_32bit)
|
||||
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)
|
||||
{
|
||||
u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
|
||||
void __iomem *addr = shdev->chan_reg + DMAOR;
|
||||
|
||||
if (shdev->pdata->dmaor_is_32bit)
|
||||
__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);
|
||||
|
||||
__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)
|
||||
{
|
||||
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++) {
|
||||
struct sh_dmae_chan *sh_chan = shdev->chan[i];
|
||||
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)
|
||||
{
|
||||
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) |
|
||||
((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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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];
|
||||
u16 __iomem *addr = shdev->dmars;
|
||||
void __iomem *addr = shdev->dmars;
|
||||
unsigned int shift = chan_pdata->dmars_bit;
|
||||
|
||||
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 */
|
||||
if (!addr)
|
||||
addr = (u16 __iomem *)shdev->chan_reg;
|
||||
addr += chan_pdata->dmars / sizeof(u16);
|
||||
addr = shdev->chan_reg;
|
||||
addr += chan_pdata->dmars;
|
||||
|
||||
__raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
|
||||
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_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;
|
||||
int i;
|
||||
|
||||
|
@ -323,7 +344,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave(
|
|||
} else {
|
||||
for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
|
||||
if (cfg->mid_rid == match) {
|
||||
sh_chan->shdma_chan.slave_id = cfg->slave_id;
|
||||
sh_chan->shdma_chan.slave_id = i;
|
||||
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,
|
||||
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,
|
||||
shdma_chan);
|
||||
|
@ -340,8 +361,10 @@ static int sh_dmae_set_slave(struct shdma_chan *schan,
|
|||
if (!cfg)
|
||||
return -ENXIO;
|
||||
|
||||
if (!try)
|
||||
if (!try) {
|
||||
sh_chan->config = cfg;
|
||||
sh_chan->slave_addr = slave_addr ? : cfg->addr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -505,7 +528,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
|
|||
struct shdma_chan *schan;
|
||||
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) {
|
||||
dev_err(sdev->dma_dev.dev,
|
||||
"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);
|
||||
|
||||
sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32);
|
||||
sh_chan->base = shdev->chan_reg + chan_pdata->offset;
|
||||
|
||||
/* set up channel irq */
|
||||
if (pdev->id >= 0)
|
||||
|
@ -541,7 +565,6 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
|
|||
err_no_irq:
|
||||
/* remove from dmaengine device node */
|
||||
shdma_chan_remove(schan);
|
||||
kfree(sh_chan);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -552,14 +575,9 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
|
|||
int 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);
|
||||
|
||||
shdma_free_irq(&sh_chan->shdma_chan);
|
||||
|
||||
shdma_chan_remove(schan);
|
||||
kfree(sh_chan);
|
||||
}
|
||||
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
|
||||
* 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)
|
||||
|
@ -658,9 +676,15 @@ static const struct shdma_ops sh_dmae_shdma_ops = {
|
|||
.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)
|
||||
{
|
||||
struct sh_dmae_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
const struct sh_dmae_pdata *pdata;
|
||||
unsigned long irqflags = IRQF_DISABLED,
|
||||
chan_flag[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 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 */
|
||||
if (!pdata || !pdata->channel_num)
|
||||
return -ENODEV;
|
||||
|
@ -696,33 +725,22 @@ static int sh_dmae_probe(struct platform_device *pdev)
|
|||
if (!chan || !errirq_res)
|
||||
return -ENODEV;
|
||||
|
||||
if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) {
|
||||
dev_err(&pdev->dev, "DMAC register region already claimed\n");
|
||||
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);
|
||||
shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
|
||||
GFP_KERNEL);
|
||||
if (!shdev) {
|
||||
dev_err(&pdev->dev, "Not enough memory\n");
|
||||
goto ealloc;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_dev = &shdev->shdma_dev.dma_dev;
|
||||
|
||||
shdev->chan_reg = ioremap(chan->start, resource_size(chan));
|
||||
if (!shdev->chan_reg)
|
||||
goto emapchan;
|
||||
shdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
|
||||
if (IS_ERR(shdev->chan_reg))
|
||||
return PTR_ERR(shdev->chan_reg);
|
||||
if (dmars) {
|
||||
shdev->dmars = ioremap(dmars->start, resource_size(dmars));
|
||||
if (!shdev->dmars)
|
||||
goto emapdmars;
|
||||
shdev->dmars = devm_ioremap_resource(&pdev->dev, dmars);
|
||||
if (IS_ERR(shdev->dmars))
|
||||
return PTR_ERR(shdev->dmars);
|
||||
}
|
||||
|
||||
if (!pdata->slave_only)
|
||||
|
@ -783,8 +801,8 @@ static int sh_dmae_probe(struct platform_device *pdev)
|
|||
|
||||
errirq = errirq_res->start;
|
||||
|
||||
err = request_irq(errirq, sh_dmae_err, irqflags,
|
||||
"DMAC Address Error", shdev);
|
||||
err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags,
|
||||
"DMAC Address Error", shdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"DMA failed requesting irq #%d, error %d\n",
|
||||
|
@ -862,7 +880,6 @@ chan_probe_err:
|
|||
sh_dmae_chan_remove(shdev);
|
||||
|
||||
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
|
||||
free_irq(errirq, shdev);
|
||||
eirq_err:
|
||||
#endif
|
||||
rst_err:
|
||||
|
@ -873,21 +890,9 @@ rst_err:
|
|||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
shdma_cleanup(&shdev->shdma_dev);
|
||||
eshdma:
|
||||
if (dmars)
|
||||
iounmap(shdev->dmars);
|
||||
emapdmars:
|
||||
iounmap(shdev->chan_reg);
|
||||
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;
|
||||
}
|
||||
|
@ -896,14 +901,9 @@ static int sh_dmae_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
|
||||
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);
|
||||
|
||||
if (errirq > 0)
|
||||
free_irq(errirq, shdev);
|
||||
|
||||
spin_lock_irq(&sh_dmae_lock);
|
||||
list_del_rcu(&shdev->node);
|
||||
spin_unlock_irq(&sh_dmae_lock);
|
||||
|
@ -913,31 +913,11 @@ static int sh_dmae_remove(struct platform_device *pdev)
|
|||
sh_dmae_chan_remove(shdev);
|
||||
shdma_cleanup(&shdev->shdma_dev);
|
||||
|
||||
if (shdev->dmars)
|
||||
iounmap(shdev->dmars);
|
||||
iounmap(shdev->chan_reg);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
|
@ -150,7 +150,8 @@ static const struct sudmac_slave_config *sudmac_find_slave(
|
|||
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);
|
||||
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;
|
||||
|
||||
shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
|
||||
struct sudmac_chan *sc = to_chan(schan);
|
||||
|
||||
BUG_ON(!schan);
|
||||
|
||||
shdma_free_irq(&sc->shdma_chan);
|
||||
shdma_chan_remove(schan);
|
||||
}
|
||||
dma_dev->chancnt = 0;
|
||||
|
@ -393,7 +391,6 @@ static int sudmac_probe(struct platform_device *pdev)
|
|||
chan_probe_err:
|
||||
sudmac_chan_remove(su_dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
shdma_cleanup(&su_dev->shdma_dev);
|
||||
|
||||
return err;
|
||||
|
@ -407,7 +404,6 @@ static int sudmac_remove(struct platform_device *pdev)
|
|||
dma_async_device_unregister(dma_dev);
|
||||
sudmac_chan_remove(su_dev);
|
||||
shdma_cleanup(&su_dev->shdma_dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,44 @@ struct sh_dmae_slave_config {
|
|||
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 {
|
||||
unsigned int offset;
|
||||
unsigned int dmars;
|
||||
unsigned int dmars_bit;
|
||||
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 {
|
||||
const struct sh_dmae_slave_config *slave;
|
||||
int slave_num;
|
||||
|
@ -59,42 +90,22 @@ struct sh_dmae_pdata {
|
|||
unsigned int needs_tend_set:1;
|
||||
unsigned int no_dmars:1;
|
||||
unsigned int chclr_present:1;
|
||||
unsigned int chclr_bitwise: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 */
|
||||
#define DMAOR_AE 0x00000004
|
||||
#define DMAOR_NMIF 0x00000002
|
||||
#define DMAOR_DME 0x00000001
|
||||
|
||||
/* 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_DEC 0x00008000
|
||||
#define DM_FIX 0x0000c000
|
||||
#define SM_INC 0x00001000
|
||||
#define SM_DEC 0x00002000
|
||||
#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_TE 0x00000002
|
||||
#define CHCR_IE 0x00000004
|
||||
|
|
|
@ -96,7 +96,7 @@ struct shdma_ops {
|
|||
dma_addr_t (*slave_addr)(struct shdma_chan *);
|
||||
int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
|
||||
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 (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
|
||||
struct shdma_desc *(*embedded_desc)(void *, int);
|
||||
|
@ -116,7 +116,6 @@ struct shdma_dev {
|
|||
|
||||
int shdma_request_irq(struct shdma_chan *, int,
|
||||
unsigned long, const char *);
|
||||
void shdma_free_irq(struct shdma_chan *);
|
||||
bool shdma_reset(struct shdma_dev *sdev);
|
||||
void shdma_chan_probe(struct shdma_dev *sdev,
|
||||
struct shdma_chan *schan, int id);
|
||||
|
|
Загрузка…
Ссылка в новой задаче