Commit d2b4a646 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma

Pull slave-dmaengine updates from Vinod Koul:
 "Once you have some time from extended weekend celebrations please
  consider pulling the following to get:
   - Various fixes and PCI driver for dw_dmac by Andy
   - DT binding for imx-dma by Markus & imx-sdma by Shawn
   - DT fixes for dmaengine by Lars
   - jz4740 dmac driver by Lars
   - and various fixes across the drivers"

What "extended weekend celebrations"?  I'm in the merge window, who has
time for extended celebrations..

* 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma: (40 commits)
  DMA: shdma: add DT support
  DMA: shdma: shdma_chan_filter() has to be in shdma-base.h
  DMA: shdma: (cosmetic) don't re-calculate a pointer
  dmaengine: at_hdmac: prepare clk before calling enable
  dmaengine/trivial: at_hdmac: add curly brackets to if/else expressions
  dmaengine: at_hdmac: remove unsuded atc_cleanup_descriptors()
  dmaengine: at_hdmac: add FIFO configuration parameter to DMA DT binding
  ARM: at91: dt: add header to define at_hdmac configuration
  MIPS: jz4740: Correct clock gate bit for DMA controller
  MIPS: jz4740: Remove custom DMA API
  MIPS: jz4740: Register jz4740 DMA device
  dma: Add a jz4740 dmaengine driver
  MIPS: jz4740: Acquire and enable DMA controller clock
  dma: mmp_tdma: disable irq when disabling dma channel
  dmaengine: PL08x: Avoid collisions with get_signal() macro
  dmaengine: dw: select DW_DMAC_BIG_ENDIAN_IO automagically
  dma: dw: add PCI part of the driver
  dma: dw: split driver to library part and platform code
  dma: move dw_dmac driver to an own directory
  dw_dmac: don't check resource with devm_ioremap_resource
  ...
parents 8dce5f3d 67eacc15
......@@ -24,8 +24,11 @@ The three cells in order are:
1. A phandle pointing to the DMA controller.
2. The memory interface (16 most significant bits), the peripheral interface
(16 less significant bits).
3. The peripheral identifier for the hardware handshaking interface. The
identifier can be different for tx and rx.
3. Parameters for the at91 DMA configuration register which are device
dependant:
- bit 7-0: peripheral identifier for the hardware handshaking interface. The
identifier can be different for tx and rx.
- bit 11-8: FIFO configuration. 0 for half FIFO, 1 for ALAP, 1 for ASAP.
Example:
......
* Freescale Direct Memory Access (DMA) Controller for i.MX
This document will only describe differences to the generic DMA Controller and
DMA request bindings as described in dma/dma.txt .
* DMA controller
Required properties:
- compatible : Should be "fsl,<chip>-dma". chip can be imx1, imx21 or imx27
- reg : Should contain DMA registers location and length
- interrupts : First item should be DMA interrupt, second one is optional and
should contain DMA Error interrupt
- #dma-cells : Has to be 1. imx-dma does not support anything else.
Optional properties:
- #dma-channels : Number of DMA channels supported. Should be 16.
- #dma-requests : Number of DMA requests supported.
Example:
dma: dma@10001000 {
compatible = "fsl,imx27-dma";
reg = <0x10001000 0x1000>;
interrupts = <32 33>;
#dma-cells = <1>;
#dma-channels = <16>;
};
* DMA client
Clients have to specify the DMA requests with phandles in a list.
Required properties:
- dmas: List of one or more DMA request specifiers. One DMA request specifier
consists of a phandle to the DMA controller followed by the integer
specifiying the request line.
- dma-names: List of string identifiers for the DMA requests. For the correct
names, have a look at the specific client driver.
Example:
sdhci1: sdhci@10013000 {
...
dmas = <&dma 7>;
dma-names = "rx-tx";
...
};
......@@ -4,14 +4,70 @@ Required properties:
- compatible : Should be "fsl,<chip>-sdma"
- reg : Should contain SDMA registers location and length
- interrupts : Should contain SDMA interrupt
- #dma-cells : Must be <3>.
The first cell specifies the DMA request/event ID. See details below
about the second and third cell.
- fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM
scripts firmware
The second cell of dma phandle specifies the peripheral type of DMA transfer.
The full ID of peripheral types can be found below.
ID transfer type
---------------------
0 MCU domain SSI
1 Shared SSI
2 MMC
3 SDHC
4 MCU domain UART
5 Shared UART
6 FIRI
7 MCU domain CSPI
8 Shared CSPI
9 SIM
10 ATA
11 CCM
12 External peripheral
13 Memory Stick Host Controller
14 Shared Memory Stick Host Controller
15 DSP
16 Memory
17 FIFO type Memory
18 SPDIF
19 IPU Memory
20 ASRC
21 ESAI
The third cell specifies the transfer priority as below.
ID transfer priority
-------------------------
0 High
1 Medium
2 Low
Examples:
sdma@83fb0000 {
compatible = "fsl,imx51-sdma", "fsl,imx35-sdma";
reg = <0x83fb0000 0x4000>;
interrupts = <6>;
#dma-cells = <3>;
fsl,sdma-ram-script-name = "sdma-imx51.bin";
};
DMA clients connected to the i.MX SDMA controller must use the format
described in the dma.txt file.
Examples:
ssi2: ssi@70014000 {
compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
reg = <0x70014000 0x4000>;
interrupts = <30>;
clocks = <&clks 49>;
dmas = <&sdma 24 1 0>,
<&sdma 25 1 0>;
dma-names = "rx", "tx";
fsl,fifo-depth = <15>;
};
* SHDMA Device Tree bindings
Sh-/r-mobile and r-car systems often have multiple identical DMA controller
instances, capable of serving any of a common set of DMA slave devices, using
the same configuration. To describe this topology we require all compatible
SHDMA DT nodes to be placed under a DMA multiplexer node. All such compatible
DMAC instances have the same number of channels and use the same DMA
descriptors. Therefore respective DMA DT bindings can also all be placed in the
multiplexer node. Even if there is only one such DMAC instance on a system, it
still has to be placed under such a multiplexer node.
* DMA multiplexer
Required properties:
- compatible: should be "renesas,shdma-mux"
- #dma-cells: should be <1>, see "dmas" property below
Optional properties (currently unused):
- dma-channels: number of DMA channels
- dma-requests: number of DMA request signals
* DMA controller
Required properties:
- compatible: should be "renesas,shdma"
Example:
dmac: dma-mux0 {
compatible = "renesas,shdma-mux";
#dma-cells = <1>;
dma-channels = <6>;
dma-requests = <256>;
reg = <0 0>; /* Needed for AUXDATA */
#address-cells = <1>;
#size-cells = <1>;
ranges;
dma0: shdma@fe008020 {
compatible = "renesas,shdma";
reg = <0xfe008020 0x270>,
<0xfe009000 0xc>;
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>;
interrupt-names = "error",
"ch0", "ch1", "ch2", "ch3",
"ch4", "ch5";
};
dma1: shdma@fe018020 {
...
};
dma2: shdma@fe028020 {
...
};
};
* DMA client
Required properties:
- dmas: a list of <[DMA multiplexer phandle] [MID/RID value]> pairs,
where MID/RID values are fixed handles, specified in the SoC
manual
- dma-names: a list of DMA channel names, one per "dmas" entry
Example:
dmas = <&dmac 0xd1
&dmac 0xd2>;
dma-names = "tx", "rx";
......@@ -7057,8 +7057,7 @@ SYNOPSYS DESIGNWARE DMAC DRIVER
M: Viresh Kumar <viresh.linux@gmail.com>
S: Maintained
F: include/linux/dw_dmac.h
F: drivers/dma/dw_dmac_regs.h
F: drivers/dma/dw_dmac.c
F: drivers/dma/dw/
SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
M: Seungwon Jeon <tgih.jun@samsung.com>
......
......@@ -182,8 +182,8 @@ static void pl08x_put_signal(const struct pl08x_channel_data *cd, int ch)
static struct pl08x_platform_data pl08x_pd = {
.slave_channels = &pl08x_slave_channels[0],
.num_slave_channels = ARRAY_SIZE(pl08x_slave_channels),
.get_signal = pl08x_get_signal,
.put_signal = pl08x_put_signal,
.get_xfer_signal = pl08x_get_signal,
.put_xfer_signal = pl08x_put_signal,
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
};
......
......@@ -56,8 +56,8 @@ struct pl08x_platform_data pl080_plat_data = {
},
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
.get_signal = pl080_get_signal,
.put_signal = pl080_put_signal,
.get_xfer_signal = pl080_get_signal,
.put_xfer_signal = pl080_put_signal,
};
/*
......
......@@ -334,8 +334,8 @@ static struct pl08x_platform_data spear6xx_pl080_plat_data = {
},
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
.get_signal = pl080_get_signal,
.put_signal = pl080_put_signal,
.get_xfer_signal = pl080_get_signal,
.put_xfer_signal = pl080_put_signal,
.slave_channels = spear600_dma_info,
.num_slave_channels = ARRAY_SIZE(spear600_dma_info),
};
......
......@@ -16,8 +16,6 @@
#ifndef __ASM_MACH_JZ4740_DMA_H__
#define __ASM_MACH_JZ4740_DMA_H__
struct jz4740_dma_chan;
enum jz4740_dma_request_type {
JZ4740_DMA_TYPE_AUTO_REQUEST = 8,
JZ4740_DMA_TYPE_UART_TRANSMIT = 20,
......@@ -33,58 +31,4 @@ enum jz4740_dma_request_type {
JZ4740_DMA_TYPE_SLCD = 30,
};
enum jz4740_dma_width {
JZ4740_DMA_WIDTH_32BIT = 0,
JZ4740_DMA_WIDTH_8BIT = 1,
JZ4740_DMA_WIDTH_16BIT = 2,
};
enum jz4740_dma_transfer_size {
JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0,
JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1,
JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2,
JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3,
JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4,
};
enum jz4740_dma_flags {
JZ4740_DMA_SRC_AUTOINC = 0x2,
JZ4740_DMA_DST_AUTOINC = 0x1,
};
enum jz4740_dma_mode {
JZ4740_DMA_MODE_SINGLE = 0,
JZ4740_DMA_MODE_BLOCK = 1,
};
struct jz4740_dma_config {
enum jz4740_dma_width src_width;
enum jz4740_dma_width dst_width;
enum jz4740_dma_transfer_size transfer_size;
enum jz4740_dma_request_type request_type;
enum jz4740_dma_flags flags;
enum jz4740_dma_mode mode;
};
typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int, void *);
struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name);
void jz4740_dma_free(struct jz4740_dma_chan *dma);
void jz4740_dma_configure(struct jz4740_dma_chan *dma,
const struct jz4740_dma_config *config);
void jz4740_dma_enable(struct jz4740_dma_chan *dma);
void jz4740_dma_disable(struct jz4740_dma_chan *dma);
void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src);
void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst);
void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count);
uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma);
void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
jz4740_dma_complete_callback_t cb);
#endif /* __ASM_JZ4740_DMA_H__ */
......@@ -32,6 +32,7 @@ extern struct platform_device jz4740_codec_device;
extern struct platform_device jz4740_adc_device;
extern struct platform_device jz4740_wdt_device;
extern struct platform_device jz4740_pwm_device;
extern struct platform_device jz4740_dma_device;
void jz4740_serial_device_register(void);
......
......@@ -4,7 +4,7 @@
# Object file lists.
obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
obj-y += prom.o irq.o time.o reset.o setup.o \
gpio.o clock.o platform.o timer.o serial.o
obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
......
......@@ -438,6 +438,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
&jz4740_rtc_device,
&jz4740_adc_device,
&jz4740_pwm_device,
&jz4740_dma_device,
&qi_lb60_gpio_keys,
&qi_lb60_pwm_beeper,
&qi_lb60_charger_device,
......
......@@ -687,7 +687,7 @@ static struct clk jz4740_clock_simple_clks[] = {
[3] = {
.name = "dma",
.parent = &jz_clk_high_speed_peripheral.clk,
.gate_bit = JZ_CLOCK_GATE_UART0,
.gate_bit = JZ_CLOCK_GATE_DMAC,
.ops = &jz_clk_simple_ops,
},
[4] = {
......
/*
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
* JZ4740 SoC DMA support
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <asm/mach-jz4740/dma.h>
#include <asm/mach-jz4740/base.h>
#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20)
#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20)
#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20)
#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20)
#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20)
#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20)
#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20)
#define JZ_REG_DMA_CTRL 0x300
#define JZ_REG_DMA_IRQ 0x304
#define JZ_REG_DMA_DOORBELL 0x308
#define JZ_REG_DMA_DOORBELL_SET 0x30C
#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31)
#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6)
#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4)
#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3)
#define JZ_DMA_STATUS_CTRL_HALT BIT(2)
#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1)
#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0)
#define JZ_DMA_CMD_SRC_INC BIT(23)
#define JZ_DMA_CMD_DST_INC BIT(22)
#define JZ_DMA_CMD_RDIL_MASK (0xf << 16)
#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14)
#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12)
#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8)
#define JZ_DMA_CMD_BLOCK_MODE BIT(7)
#define JZ_DMA_CMD_DESC_VALID BIT(4)
#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3)
#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2)
#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1)
#define JZ_DMA_CMD_LINK_ENABLE BIT(0)
#define JZ_DMA_CMD_FLAGS_OFFSET 22
#define JZ_DMA_CMD_RDIL_OFFSET 16
#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14
#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12
#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8
#define JZ_DMA_CMD_MODE_OFFSET 7
#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8)
#define JZ_DMA_CTRL_HALT BIT(3)
#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2)
#define JZ_DMA_CTRL_ENABLE BIT(0)
static void __iomem *jz4740_dma_base;
static spinlock_t jz4740_dma_lock;
static inline uint32_t jz4740_dma_read(size_t reg)
{
return readl(jz4740_dma_base + reg);
}
static inline void jz4740_dma_write(size_t reg, uint32_t val)
{
writel(val, jz4740_dma_base + reg);
}
static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask)
{
uint32_t val2;
val2 = jz4740_dma_read(reg);
val2 &= ~mask;
val2 |= val;
jz4740_dma_write(reg, val2);
}
struct jz4740_dma_chan {
unsigned int id;
void *dev;
const char *name;
enum jz4740_dma_flags flags;
uint32_t transfer_shift;
jz4740_dma_complete_callback_t complete_cb;
unsigned used:1;
};
#define JZ4740_DMA_CHANNEL(_id) { .id = _id }
struct jz4740_dma_chan jz4740_dma_channels[] = {
JZ4740_DMA_CHANNEL(0),
JZ4740_DMA_CHANNEL(1),
JZ4740_DMA_CHANNEL(2),
JZ4740_DMA_CHANNEL(3),
JZ4740_DMA_CHANNEL(4),
JZ4740_DMA_CHANNEL(5),
};
struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name)
{
unsigned int i;
struct jz4740_dma_chan *dma = NULL;
spin_lock(&jz4740_dma_lock);
for (i = 0; i < ARRAY_SIZE(jz4740_dma_channels); ++i) {
if (!jz4740_dma_channels[i].used) {
dma = &jz4740_dma_channels[i];
dma->used = 1;
break;
}
}
spin_unlock(&jz4740_dma_lock);
if (!dma)
return NULL;
dma->dev = dev;
dma->name = name;
return dma;
}
EXPORT_SYMBOL_GPL(jz4740_dma_request);
void jz4740_dma_configure(struct jz4740_dma_chan *dma,
const struct jz4740_dma_config *config)
{
uint32_t cmd;
switch (config->transfer_size) {
case JZ4740_DMA_TRANSFER_SIZE_2BYTE:
dma->transfer_shift = 1;
break;
case JZ4740_DMA_TRANSFER_SIZE_4BYTE:
dma->transfer_shift = 2;
break;
case JZ4740_DMA_TRANSFER_SIZE_16BYTE:
dma->transfer_shift = 4;
break;
case JZ4740_DMA_TRANSFER_SIZE_32BYTE:
dma->transfer_shift = 5;
break;
default:
dma->transfer_shift = 0;
break;
}
cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET;
cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET;
cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET;
cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET;
cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET;
cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE;
jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd);
jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0);
jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type);
}
EXPORT_SYMBOL_GPL(jz4740_dma_configure);
void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src)
{
jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src);
}
EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr);
void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst)
{
jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst);
}
EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr);
void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count)
{
count >>= dma->transfer_shift;
jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count);
}
EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count);
void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
jz4740_dma_complete_callback_t cb)
{
dma->complete_cb = cb;
}
EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb);
void jz4740_dma_free(struct jz4740_dma_chan *dma)
{
dma->dev = NULL;
dma->complete_cb = NULL;
dma->used = 0;
}
EXPORT_SYMBOL_GPL(jz4740_dma_free);
void jz4740_dma_enable(struct jz4740_dma_chan *dma)
{
jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id),
JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE,
JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC |
JZ_DMA_STATUS_CTRL_ENABLE);
jz4740_dma_write_mask(JZ_REG_DMA_CTRL,
JZ_DMA_CTRL_ENABLE,
JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE);
}
EXPORT_SYMBOL_GPL(jz4740_dma_enable);
void jz4740_dma_disable(struct jz4740_dma_chan *dma)
{
jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
JZ_DMA_STATUS_CTRL_ENABLE);
}
EXPORT_SYMBOL_GPL(jz4740_dma_disable);
uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma)
{
uint32_t residue;
residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id));
return residue << dma->transfer_shift;
}
EXPORT_SYMBOL_GPL(jz4740_dma_get_residue);
static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma)
{
(void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id));
jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE);
if (dma->complete_cb)
dma->complete_cb(dma, 0, dma->dev);
}
static irqreturn_t jz4740_dma_irq(int irq, void *dev_id)
{
uint32_t irq_status;
unsigned int i;
irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ);
for (i = 0; i < 6; ++i) {
if (irq_status & (1 << i))
jz4740_dma_chan_irq(&jz4740_dma_channels[i]);
}
return IRQ_HANDLED;
}
static int jz4740_dma_init(void)
{
unsigned int ret;
jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400);
if (!jz4740_dma_base)
return -EBUSY;
spin_lock_init(&jz4740_dma_lock);
ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL);
if (ret)
printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret);
return ret;
}
arch_initcall(jz4740_dma_init);
......@@ -329,3 +329,24 @@ struct platform_device jz4740_pwm_device = {
.name = "jz4740-pwm",
.id = -1,
};
/* DMA */
static struct resource jz4740_dma_resources[] = {
{
.start = JZ4740_DMAC_BASE_ADDR,
.end = JZ4740_DMAC_BASE_ADDR + 0x400 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = JZ4740_IRQ_DMAC,
.end = JZ4740_IRQ_DMAC,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device jz4740_dma_device = {
.name = "jz4740-dma",
.id = -1,
.num_resources = ARRAY_SIZE(jz4740_dma_resources),
.resource = jz4740_dma_resources,
};
......@@ -79,25 +79,7 @@ config INTEL_IOP_ADMA
help
Enable support for the Intel(R) IOP Series RAID engines.
config DW_DMAC
tristate "Synopsys DesignWare AHB DMA support"
depends on GENERIC_HARDIRQS
select DMA_ENGINE
default y if CPU_AT32AP7000
help
Support the Synopsys DesignWare AHB DMA controller. This
can be integrated in chips such as the Atmel AT32ap7000.
config DW_DMAC_BIG_ENDIAN_IO
bool "Use big endian I/O register access"
default y if AVR32
depends on DW_DMAC
help
Say yes here to use big endian I/O access when reading and writing
to the DMA controller registers. This is needed on some platforms,
like the Atmel AVR32 architecture.
If unsure, use the default setting.
source "drivers/dma/dw/Kconfig"
config AT_HDMAC
tristate "Atmel AHB DMA support"
......@@ -312,6 +294,12 @@ config MMP_PDMA
help
Support the MMP PDMA engine for PXA and MMP platfrom.
config DMA_JZ4740
tristate "JZ4740 DMA support"
depends on MACH_JZ4740
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
config DMA_ENGINE
bool
......
......@@ -15,7 +15,7 @@ obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_DW_DMAC_CORE) += dw/
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
......@@ -38,3 +38,4 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
......@@ -299,8 +299,8 @@ static int pl08x_request_mux(struct pl08x_dma_chan *plchan)
const struct pl08x_platform_data *pd = plchan->host->pd;
int ret;
if (plchan->mux_use++ == 0 && pd->get_signal) {
ret = pd->get_signal(plchan->cd);
if (plchan->mux_use++ == 0 && pd->get_xfer_signal) {
ret = pd->get_xfer_signal(plchan->cd);
if (ret < 0) {
plchan->mux_use = 0;
return ret;
......@@ -318,8 +318,8 @@ static void pl08x_release_mux(struct pl08x_dma_chan *plchan)
if (plchan->signal >= 0) {
WARN_ON(plchan->mux_use == 0);
if (--plchan->mux_use == 0 && pd->put_signal) {
pd->put_signal(plchan->cd, plchan->signal);
if (--plchan->mux_use == 0 && pd->put_xfer_signal) {
pd->put_xfer_signal(plchan->cd, plchan->signal);
plchan->signal = -1;
}
}
......
This diff is collapsed.
......@@ -182,6 +182,7 @@ struct at_lli {
* @txd: support for the async_tx api
* @desc_node: node on the channed descriptors list
* @len: total transaction bytecount
* @tx_width: transfer width
*/
struct at_desc {
/* FIRST values the hardware uses */
......@@ -192,6 +193,7 @@ struct at_desc {
struct dma_async_tx_descriptor txd;
struct list_head desc_node;
size_t len;
u32 tx_width;
};
static inline struct at_desc *
......@@ -211,6 +213,7 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
enum atc_status {
ATC_IS_ERROR = 0,
ATC_IS_PAUSED = 1,
ATC_IS_BTC = 2,
ATC_IS_CYCLIC = 24,
};
......@@ -228,6 +231,7 @@ enum atc_status {
* @save_cfg: configuration register that is saved on suspend/resume cycle
* @save_dscr: for cyclic operations, preserve next descriptor address in
* the cyclic list on suspend/resume cycle
* @remain_desc: to save remain desc length
* @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
* @lock: serializes enqueue/dequeue operations to descriptors lists
* @active_list: list of descriptors dmaengine is being running on
......@@ -246,6 +250,7 @@ struct at_dma_chan {
struct tasklet_struct tasklet;
u32 save_cfg;
u32 save_dscr;
u32 remain_desc;
struct dma_slave_config dma_sconfig;
spinlock_t lock;
......
This diff is collapsed.
#
# DMA engine configuration for dw
#
config DW_DMAC_CORE
tristate "Synopsys DesignWare AHB DMA support"
depends on GENERIC_HARDIRQS
select DMA_ENGINE
config DW_DMAC
tristate "Synopsys DesignWare AHB DMA platform driver"
select DW_DMAC_CORE
select DW_DMAC_BIG_ENDIAN_IO if AVR32
default y if CPU_AT32AP7000
help
Support the Synopsys DesignWare AHB DMA controller. This
can be integrated in chips such as the Atmel AT32ap7000.
config DW_DMAC_PCI
tristate "Synopsys DesignWare AHB DMA PCI driver"
depends on PCI
select DW_DMAC_CORE
help
Support the Synopsys DesignWare AHB DMA controller on the
platfroms that enumerate it as a PCI device. For example,
Intel Medfield has integrated this GPDMA controller.
config DW_DMAC_BIG_ENDIAN_IO
bool
obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o
dw_dmac_core-objs := core.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
dw_dmac-objs := platform.o
obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o
dw_dmac_pci-objs := pci.o
/*
* Driver for the Synopsys DesignWare DMA Controller
*
* Copyright (C) 2013 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _DW_DMAC_INTERNAL_H
#define _DW_DMAC_INTERNAL_H
#include <linux/device.h>
#include <linux/dw_dmac.h>
#include "regs.h"
/**
* struct dw_dma_chip - representation of DesignWare DMA controller hardware
* @dev: struct device of the DMA controller
* @irq: irq line
* @regs: memory mapped I/O space
* @dw: struct dw_dma that is filed by dw_dma_probe()
*/
struct dw_dma_chip {
struct device *dev;
int irq;
void __iomem *regs;
struct dw_dma *dw;
};
/* Export to the platform drivers */
int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata);
int dw_dma_remove(struct dw_dma_chip *chip);
void dw_dma_shutdown(struct dw_dma_chip *chip);
#ifdef CONFIG_PM_SLEEP
int dw_dma_suspend(struct dw_dma_chip *chip);
int dw_dma_resume(struct dw_dma_chip *chip);
#endif /* CONFIG_PM_SLEEP */
/**
* dwc_get_dms - get destination master
* @slave: pointer to the custom slave configuration
*
* Returns destination master in the custom slave configuration if defined, or
* default value otherwise.
*/
static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
{
return slave ? slave->dst_master : 0;
}
/**
* dwc_get_sms - get source master
* @slave: pointer to the custom slave configuration
*
* Returns source master in the custom slave configuration if defined, or
* default value otherwise.
*/
static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
{
return slave ? slave->src_master : 1;
}
#endif /* _DW_DMAC_INTERNAL_H */
/*
* PCI driver for the Synopsys DesignWare DMA Controller
*
* Copyright (C) 2013 Intel Corporation
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/device.h>
#include "internal.h"
static struct dw_dma_platform_data dw_pci_pdata = {
.is_private = 1,
.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
.chan_priority = CHAN_PRIORITY_ASCENDING,
};
static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
{
struct dw_dma_chip *chip;
struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
int ret;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
ret = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
if (ret) {
dev_err(&pdev->dev, "I/O memory remapping failed\n");
return ret;
}
pci_set_master(pdev);
pci_try_set_mwi(pdev);
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = &pdev->dev;
chip->regs = pcim_iomap_table(pdev)[0];
chip->irq = pdev->irq;
ret = dw_dma_probe(chip, pdata);
if (ret)
return ret;
pci_set_drvdata(pdev, chip);
return 0;
}
static void dw_pci_remove(struct pci_dev *pdev)
{
struct dw_dma_chip *chip = pci_get_drvdata(pdev);
int ret;
ret = dw_dma_remove(chip);
if (ret)
dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret);
}
static DEFINE_PCI_DEVICE_TABLE(dw_pci_id_table) = {
/* Medfield */
{ PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x0830), (kernel_ulong_t)&dw_pci_pdata },
/* BayTrail */
{ PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_pdata },
{ PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_pdata },
{ }
};
MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
static struct pci_driver dw_pci_driver = {
.name = "dw_dmac_pci",
.id_table = dw_pci_id_table,
.probe = dw_pci_probe,
.remove = dw_pci_remove,
};
module_pci_driver(dw_pci_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller PCI driver");
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
/*
* Platform driver for the Synopsys DesignWare DMA Controller
*
* Copyright (C) 2007-2008 Atmel Corporation
* Copyright (C) 2010-2011 ST Microelectronics
* Copyright (C) 2013 Intel Corporation
*
* Some parts of this driver are derived from the original dw_dmac.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/acpi.h>
#include <linux/acpi_dma.h>
#include "internal.h"
struct dw_dma_of_filter_args {
struct dw_dma *dw;
unsigned int req;
unsigned int src;
unsigned int dst;
};
static bool dw_dma_of_filter(struct dma_chan *chan, void *param)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma_of_filter_args *fargs = param;
/* Ensure the device matches our channel */
if (chan->device != &fargs->dw->dma)
return false;
dwc->request_line = fargs->req;
dwc->src_master = fargs->src;
dwc->dst_master = fargs->dst;
return true;
}
static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct dw_dma *dw = ofdma->of_dma_data;
struct dw_dma_of_filter_args fargs = {
.dw = dw,
};
dma_cap_mask_t cap;
if (dma_spec->args_count != 3)
return NULL;
fargs.req = dma_spec->args[0];
fargs.src = dma_spec->args[1];
fargs.dst = dma_spec->args[2];
if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
fargs.src >= dw->nr_masters ||
fargs.dst >= dw->nr_masters))
return NULL;
dma_cap_zero(cap);
dma_cap_set(DMA_SLAVE, cap);
/* TODO: there should be a simpler way to do this */
return dma_request_channel(cap, dw_dma_of_filter, &fargs);
}
#ifdef CONFIG_ACPI
static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct acpi_dma_spec *dma_spec = param;
if (chan->device->dev != dma_spec->dev ||
chan->chan_id != dma_spec->chan_id)
return false;
dwc->request_line = dma_spec->slave_id;
dwc->src_master = dwc_get_sms(NULL);
dwc->dst_master = dwc_get_dms(NULL);
return true;
}
static void dw_dma_acpi_controller_register(struct dw_dma *dw)
{
struct device *dev = dw->dma.dev;
struct acpi_dma_filter_info *info;
int ret;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return;
dma_cap_zero(info->dma_cap);
dma_cap_set(DMA_SLAVE, info->dma_cap);
info->filter_fn = dw_dma_acpi_filter;
ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
info);
if (ret)
dev_err(dev, "could not register acpi_dma_controller\n");
}
#else /* !CONFIG_ACPI */
static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
#endif /* !CONFIG_ACPI */
#ifdef CONFIG_OF
static struct dw_dma_platform_data *
dw_dma_parse_dt(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct dw_dma_platform_data *pdata;
u32 tmp, arr[4];
if (!np) {
dev_err(&pdev->dev, "Missing DT data\n");
return NULL;
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
return NULL;
if (of_property_read_bool(np, "is_private"))
pdata->is_private = true;
if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
pdata->chan_allocation_order = (unsigned char)tmp;
if (!of_property_read_u32(np, "chan_priority", &tmp))
pdata->chan_priority = tmp;
if (!of_property_read_u32(np, "block_size", &tmp))
pdata->block_size = tmp;
if (!of_property_read_u32(np, "dma-masters", &tmp)) {
if (tmp > 4)
return NULL;
pdata->nr_masters = tmp;
}
if (!of_property_read_u32_array(np, "data_width", arr,
pdata->nr_masters))
for (tmp = 0; tmp < pdata->nr_masters; tmp++)
pdata->data_width[tmp] = arr[tmp];
return pdata;
}
#else
static inline struct dw_dma_platform_data *
dw_dma_parse_dt(struct platform_device *pdev)
{
return NULL;
}
#endif
static int dw_probe(struct platform_device *pdev)
{
struct dw_dma_chip *chip;
struct device *dev = &pdev->dev;
struct resource *mem;
struct dw_dma_platform_data *pdata;
int err;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->irq = platform_get_irq(pdev, 0);
if (chip->irq < 0)
return chip->irq;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
chip->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
/* Apply default dma_mask if needed */
if (!dev->dma_mask) {
dev->dma_mask = &dev->coherent_dma_mask;
dev->coherent_dma_mask = DMA_BIT_MASK(32);
}
pdata = dev_get_platdata(dev);
if (!pdata)
pdata = dw_dma_parse_dt(pdev);
chip->dev = dev;
err = dw_dma_probe(chip, pdata);
if (err)
return err;
platform_set_drvdata(pdev, chip);
if (pdev->dev.of_node) {
err = of_dma_controller_register(pdev->dev.of_node,
dw_dma_of_xlate, chip->dw);
if (err)
dev_err(&pdev->dev,
"could not register of_dma_controller\n");
}
if (ACPI_HANDLE(&pdev->dev))
dw_dma_acpi_controller_register(chip->dw);
return 0;
}
static int dw_remove(struct platform_device *pdev)
{
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
if (pdev->dev.of_node)
of_dma_controller_free(pdev->dev.of_node);
return dw_dma_remove(chip);
}
static void dw_shutdown(struct platform_device *pdev)
{
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
dw_dma_shutdown(chip);
}
#ifdef CONFIG_OF
static const struct of_device_id dw_dma_of_id_table[] = {
{ .compatible = "snps,dma-spear1340" },
{}
};
MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id dw_dma_acpi_id_table[] = {
{ "INTL9C60", 0 },
{ }
};
#endif
#ifdef CONFIG_PM_SLEEP
static int dw_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
return dw_dma_suspend(chip);
}
static int dw_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
return dw_dma_resume(chip);
}
#else /* !CONFIG_PM_SLEEP */
#define dw_suspend_noirq NULL
#define dw_resume_noirq NULL
#endif /* !CONFIG_PM_SLEEP */
static const struct dev_pm_ops dw_dev_pm_ops = {
.suspend_noirq = dw_suspend_noirq,
.resume_noirq = dw_resume_noirq,
.freeze_noirq = dw_suspend_noirq,
.thaw_noirq = dw_resume_noirq,
.restore_noirq = dw_resume_noirq,
.poweroff_noirq = dw_suspend_noirq,
};
static struct platform_driver dw_driver = {
.probe = dw_probe,
.remove = dw_remove,
.shutdown = dw_shutdown,
.driver = {
.name = "dw_dmac",
.pm = &dw_dev_pm_ops,
.of_match_table = of_match_ptr(dw_dma_of_id_table),
.acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
},
};
static int __init dw_init(void)
{
return platform_driver_register(&dw_driver);
}
subsys_initcall(dw_init);
static void __exit dw_exit(void)
{
platform_driver_unregister(&dw_driver);
}
module_exit(dw_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
......@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/dw_dmac.h>
......@@ -100,6 +101,12 @@ struct dw_dma_regs {
u32 DW_PARAMS;
};
/*
* Big endian I/O access when reading and writing to the DMA controller
* registers. This is needed on some platforms, like the Atmel AVR32
* architecture.
*/
#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
#define dma_readl_native ioread32be
#define dma_writel_native iowrite32be
......
......@@ -1368,7 +1368,7 @@ static int fsldma_of_probe(struct platform_device *op)
dma_set_mask(&(op->dev), DMA_BIT_MASK(36));
dev_set_drvdata(&op->dev, fdev);
platform_set_drvdata(op, fdev);
/*
* We cannot use of_platform_bus_probe() because there is no
......@@ -1417,7 +1417,7 @@ static int fsldma_of_remove(struct platform_device *op)
struct fsldma_device *fdev;
unsigned int i;
fdev = dev_get_drvdata(&op->dev);
fdev = platform_get_drvdata(op);
dma_async_device_unregister(&fdev->common);
fsldma_free_irqs(fdev);
......@@ -1428,7 +1428,6 @@ static int fsldma_of_remove(struct platform_device *op)
}
iounmap(fdev->regs);
dev_set_drvdata(&op->dev, NULL);
kfree(fdev);
return 0;
......
......@@ -27,6 +27,8 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <asm/irq.h>
#include <linux/platform_data/dma-imx.h>
......@@ -186,6 +188,11 @@ struct imxdma_engine {
enum imx_dma_type devtype;
};
struct imxdma_filter_data {
struct imxdma_engine *imxdma;
int request;
};
static struct platform_device_id imx_dma_devtype[] = {
{
.name = "imx1-dma",
......@@ -202,6 +209,22 @@ static struct platform_device_id imx_dma_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, imx_dma_devtype);
static const struct of_device_id imx_dma_of_dev_id[] = {
{
.compatible = "fsl,imx1-dma",
.data = &imx_dma_devtype[IMX1_DMA],
}, {
.compatible = "fsl,imx21-dma",
.data = &imx_dma_devtype[IMX21_DMA],
}, {
.compatible = "fsl,imx27-dma",
.data = &imx_dma_devtype[IMX27_DMA],
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, imx_dma_of_dev_id);
static inline int is_imx1_dma(struct imxdma_engine *imxdma)
{
return imxdma->devtype == IMX1_DMA;
......@@ -996,17 +1019,55 @@ static void imxdma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&imxdma->lock, flags);
}
static bool imxdma_filter_fn(struct dma_chan *chan, void *param)
{
struct imxdma_filter_data *fdata = param;
struct imxdma_channel *imxdma_chan = to_imxdma_chan(chan);
if (chan->device->dev != fdata->imxdma->dev)
return false;
imxdma_chan->dma_request = fdata->request;
chan->private = NULL;
return true;
}
static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
int count = dma_spec->args_count;
struct imxdma_engine *imxdma = ofdma->of_dma_data;
struct imxdma_filter_data fdata = {
.imxdma = imxdma,
};
if (count != 1)
return NULL;
fdata.request = dma_spec->args[0];
return dma_request_channel(imxdma->dma_device.cap_mask,
imxdma_filter_fn, &fdata);
}
static int __init imxdma_probe(struct platform_device *pdev)
{
struct imxdma_engine *imxdma;
struct resource *res;
const struct of_device_id *of_id;
int ret, i;
int irq, irq_err;
of_id = of_match_device(imx_dma_of_dev_id, &pdev->dev);
if (of_id)
pdev->id_entry = of_id->data;
imxdma = devm_kzalloc(&pdev->dev, sizeof(*imxdma), GFP_KERNEL);
if (!imxdma)
return -ENOMEM;
imxdma->dev = &pdev->dev;
imxdma->devtype = pdev->id_entry->driver_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......@@ -1111,7 +1172,6 @@ static int __init imxdma_probe(struct platform_device *pdev)
&imxdma->dma_device.channels);
}
imxdma->dev = &pdev->dev;
imxdma->dma_device.dev = &pdev->dev;
imxdma->dma_device.device_alloc_chan_resources = imxdma_alloc_chan_resources;
......@@ -1136,8 +1196,19 @@ static int __init imxdma_probe(struct platform_device *pdev)
goto err;
}
if (pdev->dev.of_node) {
ret = of_dma_controller_register(pdev->dev.of_node,
imxdma_xlate, imxdma);
if (ret) {
dev_err(&pdev->dev, "unable to register of_dma_controller\n");
goto err_of_dma_controller;
}
}
return 0;
err_of_dma_controller:
dma_async_device_unregister(&imxdma->dma_device);
err:
clk_disable_unprepare(imxdma->dma_ipg);
clk_disable_unprepare(imxdma->dma_ahb);
......@@ -1150,6 +1221,9 @@ static int imxdma_remove(struct platform_device *pdev)
dma_async_device_unregister(&imxdma->dma_device);
if (pdev->dev.of_node)
of_dma_controller_free(pdev->dev.of_node);
clk_disable_unprepare(imxdma->dma_ipg);
clk_disable_unprepare(imxdma->dma_ahb);
......@@ -1159,6 +1233,7 @@ static int imxdma_remove(struct platform_device *pdev)
static struct platform_driver imxdma_driver = {
.driver = {
.name = "imx-dma",
.of_match_table = imx_dma_of_dev_id,
},
.id_table = imx_dma_devtype,
.remove = imxdma_remove,
......
......@@ -36,6 +36,7 @@
#include <linux/dmaengine.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <asm/irq.h>
#include <linux/platform_data/dma-imx-sdma.h>
......@@ -1296,6 +1297,35 @@ static int __init sdma_init(struct sdma_engine *sdma)
return ret;
}
static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
{
struct imx_dma_data *data = fn_param;
if (!imx_dma_is_general_purpose(chan))
return false;
chan->private = data;
return true;
}
static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct sdma_engine *sdma = ofdma->of_dma_data;
dma_cap_mask_t mask = sdma->dma_device.cap_mask;
struct imx_dma_data data;
if (dma_spec->args_count != 3)
return NULL;
data.dma_request = dma_spec->args[0];
data.peripheral_type = dma_spec->args[1];
data.priority = dma_spec->args[2];
return dma_request_channel(mask, sdma_filter_fn, &data);
}
static int __init sdma_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
......@@ -1443,10 +1473,20 @@ static int __init sdma_probe(struct platform_device *pdev)
goto err_init;
}
if (np) {
ret = of_dma_controller_register(np, sdma_xlate, sdma);
if (ret) {
dev_err(&pdev->dev, "failed to register controller\n");
goto err_register;
}
}
dev_info(sdma->dev, "initialized\n");
return 0;
err_register:
dma_async_device_unregister(&sdma->dma_device);
err_init:
kfree(sdma->script_addrs);
err_alloc:
......
......@@ -154,6 +154,10 @@ static void mmp_tdma_disable_chan(struct mmp_tdma_chan *tdmac)
{
writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
tdmac->reg_base + TDCR);
/* disable irq */
writel(0, tdmac->reg_base + TDIMR);
tdmac->status = DMA_SUCCESS;
}
......
......@@ -693,7 +693,7 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
return true;
}
struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct mxs_dma_engine *mxs_dma = ofdma->of_dma_data;
......
......@@ -35,8 +35,7 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
struct of_dma *ofdma;
list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
if ((ofdma->of_node == dma_spec->np) &&
(ofdma->of_dma_nbcells == dma_spec->args_count))
if (ofdma->of_node == dma_spec->np)
return ofdma;
pr_debug("%s: can't find DMA controller %s\n", __func__,
......@@ -64,8 +63,6 @@ int of_dma_controller_register(struct device_node *np,
void *data)
{
struct of_dma *ofdma;
int nbcells;
const __be32 *prop;
if (!np || !of_dma_xlate) {
pr_err("%s: not enough information provided\n", __func__);
......@@ -76,19 +73,7 @@ int of_dma_controller_register(struct device_node *np,
if (!ofdma)
return -ENOMEM;
prop = of_get_property(np, "#dma-cells", NULL);
if (prop)
nbcells = be32_to_cpup(prop);
if (!prop || !nbcells) {
pr_err("%s: #dma-cells property is missing or invalid\n",
__func__);
kfree(ofdma);
return -EINVAL;
}
ofdma->of_node = np;
ofdma->of_dma_nbcells = nbcells;
ofdma->of_dma_xlate = of_dma_xlate;
ofdma->of_dma_data = data;
......
......@@ -157,7 +157,6 @@ enum pl330_reqtype {
#define PERIPH_REV_R0P0 0
#define PERIPH_REV_R1P0 1
#define PERIPH_REV_R1P1 2
#define PCELL_ID 0xff0
#define CR0_PERIPH_REQ_SET (1 << 0)
#define CR0_BOOT_EN_SET (1 << 1)
......@@ -193,8 +192,6 @@ enum pl330_reqtype {
#define INTEG_CFG 0x0
#define PERIPH_ID_VAL ((PART << 0) | (DESIGNER << 12))
#define PCELL_ID_VAL 0xb105f00d
#define PL330_STATE_STOPPED (1 << 0)
#define PL330_STATE_EXECUTING (1 << 1)
#define PL330_STATE_WFE (1 << 2)
......@@ -292,7 +289,6 @@ static unsigned cmd_line;
/* Populated by the PL330 core driver for DMA API driver's info */
struct pl330_config {
u32 periph_id;
u32 pcell_id;
#define DMAC_MODE_NS (1 << 0)
unsigned int mode;
unsigned int data_bus_width:10; /* In number of bits */
......@@ -505,7 +501,7 @@ struct pl330_dmac {
/* Maximum possible events/irqs */
int events[32];
/* BUS address of MicroCode buffer */
u32 mcode_bus;
dma_addr_t mcode_bus;
/* CPU address of MicroCode buffer */
void *mcode_cpu;
/* List of all Channel threads */
......@@ -650,19 +646,6 @@ static inline bool _manager_ns(struct pl330_thread *thrd)
return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false;
}
static inline u32 get_id(struct pl330_info *pi, u32 off)
{
void __iomem *regs = pi->base;
u32 id = 0;
id |= (readb(regs + off + 0x0) << 0);
id |= (readb(regs + off + 0x4) << 8);
id |= (readb(regs + off + 0x8) << 16);
id |= (readb(regs + off + 0xc) << 24);
return id;
}
static inline u32 get_revision(u32 periph_id)
{
return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
......@@ -1986,9 +1969,6 @@ static void read_dmac_config(struct pl330_info *pi)
pi->pcfg.num_events = val;
pi->pcfg.irq_ns = readl(regs + CR3);
pi->pcfg.periph_id = get_id(pi, PERIPH_ID);
pi->pcfg.pcell_id = get_id(pi, PCELL_ID);
}
static inline void _reset_thread(struct pl330_thread *thrd)
......@@ -2098,10 +2078,8 @@ static int pl330_add(struct pl330_info *pi)
regs = pi->base;
/* Check if we can handle this DMAC */
if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
|| get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
if ((pi->pcfg.periph_id & 0xfffff) != PERIPH_ID_VAL) {
dev_err(pi->dev, "PERIPH_ID 0x%x !\n", pi->pcfg.periph_id);
return -EINVAL;
}
......@@ -2916,6 +2894,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
if (ret)
return ret;
pi->pcfg.periph_id = adev->periphid;
ret = pl330_add(pi);
if (ret)
goto probe_err1;
......
......@@ -4434,7 +4434,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
adev->dev = &ofdev->dev;
adev->common.dev = &ofdev->dev;
INIT_LIST_HEAD(&adev->common.channels);
dev_set_drvdata(&ofdev->dev, adev);
platform_set_drvdata(ofdev, adev);
/* create a channel */
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
......@@ -4547,14 +4547,13 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
*/
static int ppc440spe_adma_remove(struct platform_device *ofdev)
{
struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev);
struct ppc440spe_adma_device *adev = platform_get_drvdata(ofdev);
struct device_node *np = ofdev->dev.of_node;
struct resource res;
struct dma_chan *chan, *_chan;
struct ppc_dma_chan_ref *ref, *_ref;
struct ppc440spe_adma_chan *ppc440spe_chan;
dev_set_drvdata(&ofdev->dev, NULL);
if (adev->id < PPC440SPE_ADMA_ENGINES_NUM)
ppc440spe_adma_devices[adev->id] = -1;
......
obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o
obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
obj-$(CONFIG_SH_DMAE) += shdma.o
obj-$(CONFIG_SUDMAC) += sudmac.o
......@@ -175,7 +175,18 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
{
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops;
int ret;
int ret, match;
if (schan->dev->of_node) {
match = schan->hw_req;
ret = ops->set_slave(schan, match, true);
if (ret < 0)
return ret;
slave_id = schan->slave_id;
} else {
match = slave_id;
}
if (slave_id < 0 || slave_id >= slave_num)
return -EINVAL;
......@@ -183,7 +194,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, slave_id, false);
ret = ops->set_slave(schan, match, false);
if (ret < 0) {
clear_bit(slave_id, shdma_slave_used);
return ret;
......@@ -206,23 +217,26 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
* services would have to provide their own filters, which first would check
* the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do
* this, and only then, in case of a match, call this common filter.
* NOTE 2: This filter function is also used in the DT case by shdma_of_xlate().
* In that case the MID-RID value is used for slave channel filtering and is
* passed to this function in the "arg" parameter.
*/
bool shdma_chan_filter(struct dma_chan *chan, void *arg)
{
struct shdma_chan *schan = to_shdma_chan(chan);
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops;
int slave_id = (int)arg;
int match = (int)arg;
int ret;
if (slave_id < 0)
if (match < 0)
/* No slave requested - arbitrary channel */
return true;
if (slave_id >= slave_num)
if (!schan->dev->of_node && match >= slave_num)
return false;
ret = ops->set_slave(schan, slave_id, true);
ret = ops->set_slave(schan, match, true);
if (ret < 0)
return false;
......
/*
* SHDMA Device Tree glue
*
* Copyright (C) 2013 Renesas Electronics Inc.
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*/
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/shdma-base.h>
#define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
u32 id = dma_spec->args[0];
dma_cap_mask_t mask;
struct dma_chan *chan;
if (dma_spec->args_count != 1)
return NULL;
dma_cap_zero(mask);
/* Only slave DMA channels can be allocated via DT */
dma_cap_set(DMA_SLAVE, mask);
chan = dma_request_channel(mask, shdma_chan_filter, (void *)id);
if (chan)
to_shdma_chan(chan)->hw_req = id;
return chan;
}
static int shdma_of_probe(struct platform_device *pdev)
{
const struct of_dev_auxdata *lookup = pdev->dev.platform_data;
int ret;
if (!lookup)
return -EINVAL;
ret = of_dma_controller_register(pdev->dev.of_node,
shdma_of_xlate, pdev);
if (ret < 0)
return ret;
ret = of_platform_populate(pdev->dev.of_node, NULL, lookup, &pdev->dev);
if (ret < 0)
of_dma_controller_free(pdev->dev.of_node);
return ret;
}
static const struct of_device_id shdma_of_match[] = {
{ .compatible = "renesas,shdma-mux", },
{ }
};
MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
static struct platform_driver shdma_of = {
.driver = {
.owner = THIS_MODULE,
.name = "shdma-of",
.of_match_table = shdma_of_match,
},
.probe = shdma_of_probe,
};
module_platform_driver(shdma_of);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SH-DMA driver DT glue");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
......@@ -301,20 +301,32 @@ static void sh_dmae_setup_xfer(struct shdma_chan *schan,
}
}
/*
* Find a slave channel configuration from the contoller list by either a slave
* ID in the non-DT case, or by a MID/RID value in the DT case
*/
static const struct sh_dmae_slave_config *dmae_find_slave(
struct sh_dmae_chan *sh_chan, int slave_id)
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_slave_config *cfg;
int i;
if (slave_id >= SH_DMA_SLAVE_NUMBER)
return NULL;
if (!sh_chan->shdma_chan.dev->of_node) {
if (match >= SH_DMA_SLAVE_NUMBER)
return NULL;
for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
if (cfg->slave_id == slave_id)
return cfg;
for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
if (cfg->slave_id == match)
return cfg;
} 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;
return cfg;
}
}
return NULL;
}
......@@ -729,7 +741,7 @@ static int sh_dmae_probe(struct platform_device *pdev)
goto eshdma;
/* platform data */
shdev->pdata = pdev->dev.platform_data;
shdev->pdata = pdata;
if (pdata->chcr_offset)
shdev->chcr_offset = pdata->chcr_offset;
......@@ -920,11 +932,18 @@ static int sh_dmae_remove(struct platform_device *pdev)
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,
.pm = &sh_dmae_pm,
.name = SH_DMAE_DRV_NAME,
.of_match_table = sh_dmae_of_match,
},
.remove = sh_dmae_remove,
.shutdown = sh_dmae_shutdown,
......
......@@ -466,12 +466,29 @@ static enum dma_status
sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
unsigned long flags;
enum dma_status ret;
struct sirfsoc_dma_desc *sdesc;
int cid = schan->chan.chan_id;
unsigned long dma_pos;
unsigned long dma_request_bytes;
unsigned long residue;
spin_lock_irqsave(&schan->lock, flags);
sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
node);
dma_request_bytes = (sdesc->xlen + 1) * (sdesc->ylen + 1) *
(sdesc->width * SIRFSOC_DMA_WORD_LEN);
ret = dma_cookie_status(chan, cookie, txstate);
dma_pos = readl_relaxed(sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_ADDR)
<< 2;
residue = dma_request_bytes - (dma_pos - sdesc->addr);
dma_set_residue(txstate, residue);
spin_unlock_irqrestore(&schan->lock, flags);
return ret;
......
......@@ -1191,6 +1191,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
list_splice_init(&tdc->free_dma_desc, &dma_desc_list);
INIT_LIST_HEAD(&tdc->cb_desc);
tdc->config_init = false;
tdc->isr_handler = NULL;
spin_unlock_irqrestore(&tdc->lock, flags);
while (!list_empty(&dma_desc_list)) {
......@@ -1334,7 +1335,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"request_irq failed with err %d channel %d\n",
i, ret);
ret, i);
goto err_irq;
}
......
......@@ -811,8 +811,6 @@ static int td_remove(struct platform_device *pdev)
kfree(td);
release_mem_region(iomem->start, resource_size(iomem));
platform_set_drvdata(pdev, NULL);
dev_dbg(&pdev->dev, "Removed...\n");
return 0;
}
......
......@@ -76,11 +76,11 @@ struct pl08x_channel_data {
* platform, all inclusive, including multiplexed channels. The available
* physical channels will be multiplexed around these signals as they are
* requested, just enumerate all possible channels.
* @get_signal: request a physical signal to be used for a DMA transfer
* @get_xfer_signal: request a physical signal to be used for a DMA transfer
* immediately: if there is some multiplexing or similar blocking the use
* of the channel the transfer can be denied by returning less than zero,
* else it returns the allocated signal number
* @put_signal: indicate to the platform that this physical signal is not
* @put_xfer_signal: indicate to the platform that this physical signal is not
* running any DMA transfer and multiplexing can be recycled
* @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2
* @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2
......@@ -89,8 +89,8 @@ struct pl08x_platform_data {
const struct pl08x_channel_data *slave_channels;
unsigned int num_slave_channels;
struct pl08x_channel_data memcpy_channel;
int (*get_signal)(const struct pl08x_channel_data *);
void (*put_signal)(const struct pl08x_channel_data *, int);
int (*get_xfer_signal)(const struct pl08x_channel_data *);
void (*put_xfer_signal)(const struct pl08x_channel_data *, int);
u8 lli_buses;
u8 mem_buses;
};
......
......@@ -21,7 +21,6 @@ struct device_node;
struct of_dma {
struct list_head of_dma_controllers;
struct device_node *of_node;
int of_dma_nbcells;
struct dma_chan *(*of_dma_xlate)
(struct of_phandle_args *, struct of_dma *);
void *of_dma_data;
......
......@@ -35,16 +35,20 @@ struct at_dma_slave {
/* Platform-configurable bits in CFG */
#define ATC_PER_MSB(h) ((0x30U & (h)) >> 4) /* Extract most significant bits of a handshaking identifier */
#define ATC_SRC_PER(h) (0xFU & (h)) /* Channel src rq associated with periph handshaking ifc h */
#define ATC_DST_PER(h) ((0xFU & (h)) << 4) /* Channel dst rq associated with periph handshaking ifc h */
#define ATC_SRC_REP (0x1 << 8) /* Source Replay Mod */
#define ATC_SRC_H2SEL (0x1 << 9) /* Source Handshaking Mod */
#define ATC_SRC_H2SEL_SW (0x0 << 9)
#define ATC_SRC_H2SEL_HW (0x1 << 9)
#define ATC_SRC_PER_MSB(h) (ATC_PER_MSB(h) << 10) /* Channel src rq (most significant bits) */
#define ATC_DST_REP (0x1 << 12) /* Destination Replay Mod */
#define ATC_DST_H2SEL (0x1 << 13) /* Destination Handshaking Mod */
#define ATC_DST_H2SEL_SW (0x0 << 13)
#define ATC_DST_H2SEL_HW (0x1 << 13)
#define ATC_DST_PER_MSB(h) (ATC_PER_MSB(h) << 14) /* Channel dst rq (most significant bits) */
#define ATC_SOD (0x1 << 16) /* Stop On Done */
#define ATC_LOCK_IF (0x1 << 20) /* Interface Lock */
#define ATC_LOCK_B (0x1 << 21) /* AHB Bus Lock */
......
......@@ -60,10 +60,8 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan)
static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
{
return strstr(dev_name(chan->device->dev), "sdma") ||
!strcmp(dev_name(chan->device->dev), "imx1-dma") ||
!strcmp(dev_name(chan->device->dev), "imx21-dma") ||
!strcmp(dev_name(chan->device->dev), "imx27-dma");
return !strcmp(chan->device->dev->driver->name, "imx-sdma") ||
!strcmp(chan->device->dev->driver->name, "imx-dma");
}
#endif
......@@ -99,6 +99,4 @@ struct sh_dmae_pdata {
#define CHCR_TE 0x00000002
#define CHCR_IE 0x00000004
bool shdma_chan_filter(struct dma_chan *chan, void *arg);
#endif
......@@ -68,6 +68,8 @@ struct shdma_chan {
int id; /* Raw id of this channel */
int irq; /* Channel IRQ */
int slave_id; /* Client ID for slave DMA */
int hw_req; /* DMA request line for slave DMA - same
* as MID/RID, used with DT */
enum shdma_pm_state pm_state;
};
......@@ -122,5 +124,6 @@ void shdma_chan_remove(struct shdma_chan *schan);
int shdma_init(struct device *dev, struct shdma_dev *sdev,
int chan_num);
void shdma_cleanup(struct shdma_dev *sdev);
bool shdma_chan_filter(struct dma_chan *chan, void *arg);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment