You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branches 'dma40', 'pl08x', 'fsldma', 'imx' and 'intel-mid' into dmaengine
This commit is contained in:
@@ -49,6 +49,14 @@ config INTEL_MID_DMAC
|
||||
config ASYNC_TX_DISABLE_CHANNEL_SWITCH
|
||||
bool
|
||||
|
||||
config AMBA_PL08X
|
||||
bool "ARM PrimeCell PL080 or PL081 support"
|
||||
depends on ARM_AMBA && EXPERIMENTAL
|
||||
select DMA_ENGINE
|
||||
help
|
||||
Platform has a PL08x DMAC device
|
||||
which can provide DMA engine support
|
||||
|
||||
config INTEL_IOATDMA
|
||||
tristate "Intel I/OAT DMA support"
|
||||
depends on PCI && X86
|
||||
@@ -195,6 +203,22 @@ config PCH_DMA
|
||||
help
|
||||
Enable support for the Topcliff PCH DMA engine.
|
||||
|
||||
config IMX_SDMA
|
||||
tristate "i.MX SDMA support"
|
||||
depends on ARCH_MX25 || ARCH_MX3 || ARCH_MX5
|
||||
select DMA_ENGINE
|
||||
help
|
||||
Support the i.MX SDMA engine. This engine is integrated into
|
||||
Freescale i.MX25/31/35/51 chips.
|
||||
|
||||
config IMX_DMA
|
||||
tristate "i.MX DMA support"
|
||||
depends on ARCH_MX1 || ARCH_MX21 || MACH_MX27
|
||||
select DMA_ENGINE
|
||||
help
|
||||
Support the i.MX DMA engine. This engine is integrated into
|
||||
Freescale i.MX1/21/27 chips.
|
||||
|
||||
config DMA_ENGINE
|
||||
bool
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
|
||||
obj-$(CONFIG_SH_DMAE) += shdma.o
|
||||
obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
|
||||
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
|
||||
obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
|
||||
obj-$(CONFIG_IMX_DMA) += imx-dma.o
|
||||
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
|
||||
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
|
||||
obj-$(CONFIG_PL330_DMA) += pl330.o
|
||||
obj-$(CONFIG_PCH_DMA) += pch_dma.o
|
||||
obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -690,8 +690,12 @@ int dma_async_device_register(struct dma_device *device)
|
||||
!device->device_prep_dma_memset);
|
||||
BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
|
||||
!device->device_prep_dma_interrupt);
|
||||
BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
|
||||
!device->device_prep_dma_sg);
|
||||
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
|
||||
!device->device_prep_slave_sg);
|
||||
BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) &&
|
||||
!device->device_prep_dma_cyclic);
|
||||
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
|
||||
!device->device_control);
|
||||
|
||||
|
||||
+169
-185
@@ -35,9 +35,10 @@
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/fsldma.h>
|
||||
#include "fsldma.h"
|
||||
|
||||
static const char msg_ld_oom[] = "No free memory for link descriptor\n";
|
||||
|
||||
static void dma_init(struct fsldma_chan *chan)
|
||||
{
|
||||
/* Reset the channel */
|
||||
@@ -499,7 +500,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
|
||||
|
||||
new = fsl_dma_alloc_descriptor(chan);
|
||||
if (!new) {
|
||||
dev_err(chan->dev, "No free memory for link descriptor\n");
|
||||
dev_err(chan->dev, msg_ld_oom);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -536,8 +537,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
|
||||
/* Allocate the link descriptor from DMA pool */
|
||||
new = fsl_dma_alloc_descriptor(chan);
|
||||
if (!new) {
|
||||
dev_err(chan->dev,
|
||||
"No free memory for link descriptor\n");
|
||||
dev_err(chan->dev, msg_ld_oom);
|
||||
goto fail;
|
||||
}
|
||||
#ifdef FSL_DMA_LD_DEBUG
|
||||
@@ -583,6 +583,125 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
|
||||
struct scatterlist *dst_sg, unsigned int dst_nents,
|
||||
struct scatterlist *src_sg, unsigned int src_nents,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
|
||||
struct fsldma_chan *chan = to_fsl_chan(dchan);
|
||||
size_t dst_avail, src_avail;
|
||||
dma_addr_t dst, src;
|
||||
size_t len;
|
||||
|
||||
/* basic sanity checks */
|
||||
if (dst_nents == 0 || src_nents == 0)
|
||||
return NULL;
|
||||
|
||||
if (dst_sg == NULL || src_sg == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* TODO: should we check that both scatterlists have the same
|
||||
* TODO: number of bytes in total? Is that really an error?
|
||||
*/
|
||||
|
||||
/* get prepared for the loop */
|
||||
dst_avail = sg_dma_len(dst_sg);
|
||||
src_avail = sg_dma_len(src_sg);
|
||||
|
||||
/* run until we are out of scatterlist entries */
|
||||
while (true) {
|
||||
|
||||
/* create the largest transaction possible */
|
||||
len = min_t(size_t, src_avail, dst_avail);
|
||||
len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT);
|
||||
if (len == 0)
|
||||
goto fetch;
|
||||
|
||||
dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail;
|
||||
src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail;
|
||||
|
||||
/* allocate and populate the descriptor */
|
||||
new = fsl_dma_alloc_descriptor(chan);
|
||||
if (!new) {
|
||||
dev_err(chan->dev, msg_ld_oom);
|
||||
goto fail;
|
||||
}
|
||||
#ifdef FSL_DMA_LD_DEBUG
|
||||
dev_dbg(chan->dev, "new link desc alloc %p\n", new);
|
||||
#endif
|
||||
|
||||
set_desc_cnt(chan, &new->hw, len);
|
||||
set_desc_src(chan, &new->hw, src);
|
||||
set_desc_dst(chan, &new->hw, dst);
|
||||
|
||||
if (!first)
|
||||
first = new;
|
||||
else
|
||||
set_desc_next(chan, &prev->hw, new->async_tx.phys);
|
||||
|
||||
new->async_tx.cookie = 0;
|
||||
async_tx_ack(&new->async_tx);
|
||||
prev = new;
|
||||
|
||||
/* Insert the link descriptor to the LD ring */
|
||||
list_add_tail(&new->node, &first->tx_list);
|
||||
|
||||
/* update metadata */
|
||||
dst_avail -= len;
|
||||
src_avail -= len;
|
||||
|
||||
fetch:
|
||||
/* fetch the next dst scatterlist entry */
|
||||
if (dst_avail == 0) {
|
||||
|
||||
/* no more entries: we're done */
|
||||
if (dst_nents == 0)
|
||||
break;
|
||||
|
||||
/* fetch the next entry: if there are no more: done */
|
||||
dst_sg = sg_next(dst_sg);
|
||||
if (dst_sg == NULL)
|
||||
break;
|
||||
|
||||
dst_nents--;
|
||||
dst_avail = sg_dma_len(dst_sg);
|
||||
}
|
||||
|
||||
/* fetch the next src scatterlist entry */
|
||||
if (src_avail == 0) {
|
||||
|
||||
/* no more entries: we're done */
|
||||
if (src_nents == 0)
|
||||
break;
|
||||
|
||||
/* fetch the next entry: if there are no more: done */
|
||||
src_sg = sg_next(src_sg);
|
||||
if (src_sg == NULL)
|
||||
break;
|
||||
|
||||
src_nents--;
|
||||
src_avail = sg_dma_len(src_sg);
|
||||
}
|
||||
}
|
||||
|
||||
new->async_tx.flags = flags; /* client is in control of this ack */
|
||||
new->async_tx.cookie = -EBUSY;
|
||||
|
||||
/* Set End-of-link to the last link descriptor of new list */
|
||||
set_ld_eol(chan, new);
|
||||
|
||||
return &first->async_tx;
|
||||
|
||||
fail:
|
||||
if (!first)
|
||||
return NULL;
|
||||
|
||||
fsldma_free_desc_list_reverse(chan, &first->tx_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
|
||||
* @chan: DMA channel
|
||||
@@ -599,207 +718,70 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
|
||||
struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
|
||||
enum dma_data_direction direction, unsigned long flags)
|
||||
{
|
||||
struct fsldma_chan *chan;
|
||||
struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
|
||||
struct fsl_dma_slave *slave;
|
||||
size_t copy;
|
||||
|
||||
int i;
|
||||
struct scatterlist *sg;
|
||||
size_t sg_used;
|
||||
size_t hw_used;
|
||||
struct fsl_dma_hw_addr *hw;
|
||||
dma_addr_t dma_dst, dma_src;
|
||||
|
||||
if (!dchan)
|
||||
return NULL;
|
||||
|
||||
if (!dchan->private)
|
||||
return NULL;
|
||||
|
||||
chan = to_fsl_chan(dchan);
|
||||
slave = dchan->private;
|
||||
|
||||
if (list_empty(&slave->addresses))
|
||||
return NULL;
|
||||
|
||||
hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry);
|
||||
hw_used = 0;
|
||||
|
||||
/*
|
||||
* Build the hardware transaction to copy from the scatterlist to
|
||||
* the hardware, or from the hardware to the scatterlist
|
||||
* This operation is not supported on the Freescale DMA controller
|
||||
*
|
||||
* If you are copying from the hardware to the scatterlist and it
|
||||
* takes two hardware entries to fill an entire page, then both
|
||||
* hardware entries will be coalesced into the same page
|
||||
*
|
||||
* If you are copying from the scatterlist to the hardware and a
|
||||
* single page can fill two hardware entries, then the data will
|
||||
* be read out of the page into the first hardware entry, and so on
|
||||
* However, we need to provide the function pointer to allow the
|
||||
* device_control() method to work.
|
||||
*/
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
sg_used = 0;
|
||||
|
||||
/* Loop until the entire scatterlist entry is used */
|
||||
while (sg_used < sg_dma_len(sg)) {
|
||||
|
||||
/*
|
||||
* If we've used up the current hardware address/length
|
||||
* pair, we need to load a new one
|
||||
*
|
||||
* This is done in a while loop so that descriptors with
|
||||
* length == 0 will be skipped
|
||||
*/
|
||||
while (hw_used >= hw->length) {
|
||||
|
||||
/*
|
||||
* If the current hardware entry is the last
|
||||
* entry in the list, we're finished
|
||||
*/
|
||||
if (list_is_last(&hw->entry, &slave->addresses))
|
||||
goto finished;
|
||||
|
||||
/* Get the next hardware address/length pair */
|
||||
hw = list_entry(hw->entry.next,
|
||||
struct fsl_dma_hw_addr, entry);
|
||||
hw_used = 0;
|
||||
}
|
||||
|
||||
/* Allocate the link descriptor from DMA pool */
|
||||
new = fsl_dma_alloc_descriptor(chan);
|
||||
if (!new) {
|
||||
dev_err(chan->dev, "No free memory for "
|
||||
"link descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
#ifdef FSL_DMA_LD_DEBUG
|
||||
dev_dbg(chan->dev, "new link desc alloc %p\n", new);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Calculate the maximum number of bytes to transfer,
|
||||
* making sure it is less than the DMA controller limit
|
||||
*/
|
||||
copy = min_t(size_t, sg_dma_len(sg) - sg_used,
|
||||
hw->length - hw_used);
|
||||
copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT);
|
||||
|
||||
/*
|
||||
* DMA_FROM_DEVICE
|
||||
* from the hardware to the scatterlist
|
||||
*
|
||||
* DMA_TO_DEVICE
|
||||
* from the scatterlist to the hardware
|
||||
*/
|
||||
if (direction == DMA_FROM_DEVICE) {
|
||||
dma_src = hw->address + hw_used;
|
||||
dma_dst = sg_dma_address(sg) + sg_used;
|
||||
} else {
|
||||
dma_src = sg_dma_address(sg) + sg_used;
|
||||
dma_dst = hw->address + hw_used;
|
||||
}
|
||||
|
||||
/* Fill in the descriptor */
|
||||
set_desc_cnt(chan, &new->hw, copy);
|
||||
set_desc_src(chan, &new->hw, dma_src);
|
||||
set_desc_dst(chan, &new->hw, dma_dst);
|
||||
|
||||
/*
|
||||
* If this is not the first descriptor, chain the
|
||||
* current descriptor after the previous descriptor
|
||||
*/
|
||||
if (!first) {
|
||||
first = new;
|
||||
} else {
|
||||
set_desc_next(chan, &prev->hw,
|
||||
new->async_tx.phys);
|
||||
}
|
||||
|
||||
new->async_tx.cookie = 0;
|
||||
async_tx_ack(&new->async_tx);
|
||||
|
||||
prev = new;
|
||||
sg_used += copy;
|
||||
hw_used += copy;
|
||||
|
||||
/* Insert the link descriptor into the LD ring */
|
||||
list_add_tail(&new->node, &first->tx_list);
|
||||
}
|
||||
}
|
||||
|
||||
finished:
|
||||
|
||||
/* All of the hardware address/length pairs had length == 0 */
|
||||
if (!first || !new)
|
||||
return NULL;
|
||||
|
||||
new->async_tx.flags = flags;
|
||||
new->async_tx.cookie = -EBUSY;
|
||||
|
||||
/* Set End-of-link to the last link descriptor of new list */
|
||||
set_ld_eol(chan, new);
|
||||
|
||||
/* Enable extra controller features */
|
||||
if (chan->set_src_loop_size)
|
||||
chan->set_src_loop_size(chan, slave->src_loop_size);
|
||||
|
||||
if (chan->set_dst_loop_size)
|
||||
chan->set_dst_loop_size(chan, slave->dst_loop_size);
|
||||
|
||||
if (chan->toggle_ext_start)
|
||||
chan->toggle_ext_start(chan, slave->external_start);
|
||||
|
||||
if (chan->toggle_ext_pause)
|
||||
chan->toggle_ext_pause(chan, slave->external_pause);
|
||||
|
||||
if (chan->set_request_count)
|
||||
chan->set_request_count(chan, slave->request_count);
|
||||
|
||||
return &first->async_tx;
|
||||
|
||||
fail:
|
||||
/* If first was not set, then we failed to allocate the very first
|
||||
* descriptor, and we're done */
|
||||
if (!first)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* First is set, so all of the descriptors we allocated have been added
|
||||
* to first->tx_list, INCLUDING "first" itself. Therefore we
|
||||
* must traverse the list backwards freeing each descriptor in turn
|
||||
*
|
||||
* We're re-using variables for the loop, oh well
|
||||
*/
|
||||
fsldma_free_desc_list_reverse(chan, &first->tx_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int fsl_dma_device_control(struct dma_chan *dchan,
|
||||
enum dma_ctrl_cmd cmd, unsigned long arg)
|
||||
{
|
||||
struct dma_slave_config *config;
|
||||
struct fsldma_chan *chan;
|
||||
unsigned long flags;
|
||||
|
||||
/* Only supports DMA_TERMINATE_ALL */
|
||||
if (cmd != DMA_TERMINATE_ALL)
|
||||
return -ENXIO;
|
||||
int size;
|
||||
|
||||
if (!dchan)
|
||||
return -EINVAL;
|
||||
|
||||
chan = to_fsl_chan(dchan);
|
||||
|
||||
/* Halt the DMA engine */
|
||||
dma_halt(chan);
|
||||
switch (cmd) {
|
||||
case DMA_TERMINATE_ALL:
|
||||
/* Halt the DMA engine */
|
||||
dma_halt(chan);
|
||||
|
||||
spin_lock_irqsave(&chan->desc_lock, flags);
|
||||
spin_lock_irqsave(&chan->desc_lock, flags);
|
||||
|
||||
/* Remove and free all of the descriptors in the LD queue */
|
||||
fsldma_free_desc_list(chan, &chan->ld_pending);
|
||||
fsldma_free_desc_list(chan, &chan->ld_running);
|
||||
/* Remove and free all of the descriptors in the LD queue */
|
||||
fsldma_free_desc_list(chan, &chan->ld_pending);
|
||||
fsldma_free_desc_list(chan, &chan->ld_running);
|
||||
|
||||
spin_unlock_irqrestore(&chan->desc_lock, flags);
|
||||
spin_unlock_irqrestore(&chan->desc_lock, flags);
|
||||
return 0;
|
||||
|
||||
case DMA_SLAVE_CONFIG:
|
||||
config = (struct dma_slave_config *)arg;
|
||||
|
||||
/* make sure the channel supports setting burst size */
|
||||
if (!chan->set_request_count)
|
||||
return -ENXIO;
|
||||
|
||||
/* we set the controller burst size depending on direction */
|
||||
if (config->direction == DMA_TO_DEVICE)
|
||||
size = config->dst_addr_width * config->dst_maxburst;
|
||||
else
|
||||
size = config->src_addr_width * config->src_maxburst;
|
||||
|
||||
chan->set_request_count(chan, size);
|
||||
return 0;
|
||||
|
||||
case FSLDMA_EXTERNAL_START:
|
||||
|
||||
/* make sure the channel supports external start */
|
||||
if (!chan->toggle_ext_start)
|
||||
return -ENXIO;
|
||||
|
||||
chan->toggle_ext_start(chan, arg);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1327,11 +1309,13 @@ static int __devinit fsldma_of_probe(struct platform_device *op,
|
||||
|
||||
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
|
||||
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
|
||||
dma_cap_set(DMA_SG, fdev->common.cap_mask);
|
||||
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
|
||||
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
|
||||
fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
|
||||
fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
|
||||
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
|
||||
fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
|
||||
fdev->common.device_tx_status = fsl_tx_status;
|
||||
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
|
||||
fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* drivers/dma/imx-dma.c
|
||||
*
|
||||
* This file contains a driver for the Freescale i.MX DMA engine
|
||||
* found on i.MX1/21/27
|
||||
*
|
||||
* Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <mach/dma-v1.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
struct imxdma_channel {
|
||||
struct imxdma_engine *imxdma;
|
||||
unsigned int channel;
|
||||
unsigned int imxdma_channel;
|
||||
|
||||
enum dma_slave_buswidth word_size;
|
||||
dma_addr_t per_address;
|
||||
u32 watermark_level;
|
||||
struct dma_chan chan;
|
||||
spinlock_t lock;
|
||||
struct dma_async_tx_descriptor desc;
|
||||
dma_cookie_t last_completed;
|
||||
enum dma_status status;
|
||||
int dma_request;
|
||||
struct scatterlist *sg_list;
|
||||
};
|
||||
|
||||
#define MAX_DMA_CHANNELS 8
|
||||
|
||||
struct imxdma_engine {
|
||||
struct device *dev;
|
||||
struct dma_device dma_device;
|
||||
struct imxdma_channel channel[MAX_DMA_CHANNELS];
|
||||
};
|
||||
|
||||
static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
|
||||
{
|
||||
return container_of(chan, struct imxdma_channel, chan);
|
||||
}
|
||||
|
||||
static void imxdma_handle(struct imxdma_channel *imxdmac)
|
||||
{
|
||||
if (imxdmac->desc.callback)
|
||||
imxdmac->desc.callback(imxdmac->desc.callback_param);
|
||||
imxdmac->last_completed = imxdmac->desc.cookie;
|
||||
}
|
||||
|
||||
static void imxdma_irq_handler(int channel, void *data)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = data;
|
||||
|
||||
imxdmac->status = DMA_SUCCESS;
|
||||
imxdma_handle(imxdmac);
|
||||
}
|
||||
|
||||
static void imxdma_err_handler(int channel, void *data, int error)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = data;
|
||||
|
||||
imxdmac->status = DMA_ERROR;
|
||||
imxdma_handle(imxdmac);
|
||||
}
|
||||
|
||||
static void imxdma_progression(int channel, void *data,
|
||||
struct scatterlist *sg)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = data;
|
||||
|
||||
imxdmac->status = DMA_SUCCESS;
|
||||
imxdma_handle(imxdmac);
|
||||
}
|
||||
|
||||
static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
|
||||
struct dma_slave_config *dmaengine_cfg = (void *)arg;
|
||||
int ret;
|
||||
unsigned int mode = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case DMA_TERMINATE_ALL:
|
||||
imxdmac->status = DMA_ERROR;
|
||||
imx_dma_disable(imxdmac->imxdma_channel);
|
||||
return 0;
|
||||
case DMA_SLAVE_CONFIG:
|
||||
if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
|
||||
imxdmac->per_address = dmaengine_cfg->src_addr;
|
||||
imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
|
||||
imxdmac->word_size = dmaengine_cfg->src_addr_width;
|
||||
} else {
|
||||
imxdmac->per_address = dmaengine_cfg->dst_addr;
|
||||
imxdmac->watermark_level = dmaengine_cfg->dst_maxburst;
|
||||
imxdmac->word_size = dmaengine_cfg->dst_addr_width;
|
||||
}
|
||||
|
||||
switch (imxdmac->word_size) {
|
||||
case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
||||
mode = IMX_DMA_MEMSIZE_8;
|
||||
break;
|
||||
case DMA_SLAVE_BUSWIDTH_2_BYTES:
|
||||
mode = IMX_DMA_MEMSIZE_16;
|
||||
break;
|
||||
default:
|
||||
case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
||||
mode = IMX_DMA_MEMSIZE_32;
|
||||
break;
|
||||
}
|
||||
ret = imx_dma_config_channel(imxdmac->imxdma_channel,
|
||||
mode | IMX_DMA_TYPE_FIFO,
|
||||
IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
|
||||
imxdmac->dma_request, 1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
imx_dma_config_burstlen(imxdmac->imxdma_channel, imxdmac->watermark_level);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static enum dma_status imxdma_tx_status(struct dma_chan *chan,
|
||||
dma_cookie_t cookie,
|
||||
struct dma_tx_state *txstate)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
|
||||
dma_cookie_t last_used;
|
||||
enum dma_status ret;
|
||||
|
||||
last_used = chan->cookie;
|
||||
|
||||
ret = dma_async_is_complete(cookie, imxdmac->last_completed, last_used);
|
||||
dma_set_tx_state(txstate, imxdmac->last_completed, last_used, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static dma_cookie_t imxdma_assign_cookie(struct imxdma_channel *imxdma)
|
||||
{
|
||||
dma_cookie_t cookie = imxdma->chan.cookie;
|
||||
|
||||
if (++cookie < 0)
|
||||
cookie = 1;
|
||||
|
||||
imxdma->chan.cookie = cookie;
|
||||
imxdma->desc.cookie = cookie;
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
|
||||
dma_cookie_t cookie;
|
||||
|
||||
spin_lock_irq(&imxdmac->lock);
|
||||
|
||||
cookie = imxdma_assign_cookie(imxdmac);
|
||||
|
||||
imx_dma_enable(imxdmac->imxdma_channel);
|
||||
|
||||
spin_unlock_irq(&imxdmac->lock);
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
static int imxdma_alloc_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
|
||||
struct imx_dma_data *data = chan->private;
|
||||
|
||||
imxdmac->dma_request = data->dma_request;
|
||||
|
||||
dma_async_tx_descriptor_init(&imxdmac->desc, chan);
|
||||
imxdmac->desc.tx_submit = imxdma_tx_submit;
|
||||
/* txd.flags will be overwritten in prep funcs */
|
||||
imxdmac->desc.flags = DMA_CTRL_ACK;
|
||||
|
||||
imxdmac->status = DMA_SUCCESS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imxdma_free_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
|
||||
|
||||
imx_dma_disable(imxdmac->imxdma_channel);
|
||||
|
||||
if (imxdmac->sg_list) {
|
||||
kfree(imxdmac->sg_list);
|
||||
imxdmac->sg_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
|
||||
struct dma_chan *chan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_data_direction direction,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
|
||||
struct scatterlist *sg;
|
||||
int i, ret, dma_length = 0;
|
||||
unsigned int dmamode;
|
||||
|
||||
if (imxdmac->status == DMA_IN_PROGRESS)
|
||||
return NULL;
|
||||
|
||||
imxdmac->status = DMA_IN_PROGRESS;
|
||||
|
||||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
dma_length += sg->length;
|
||||
}
|
||||
|
||||
if (direction == DMA_FROM_DEVICE)
|
||||
dmamode = DMA_MODE_READ;
|
||||
else
|
||||
dmamode = DMA_MODE_WRITE;
|
||||
|
||||
ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
|
||||
dma_length, imxdmac->per_address, dmamode);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
return &imxdmac->desc;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
|
||||
struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
|
||||
size_t period_len, enum dma_data_direction direction)
|
||||
{
|
||||
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
|
||||
struct imxdma_engine *imxdma = imxdmac->imxdma;
|
||||
int i, ret;
|
||||
unsigned int periods = buf_len / period_len;
|
||||
unsigned int dmamode;
|
||||
|
||||
dev_dbg(imxdma->dev, "%s channel: %d buf_len=%d period_len=%d\n",
|
||||
__func__, imxdmac->channel, buf_len, period_len);
|
||||
|
||||
if (imxdmac->status == DMA_IN_PROGRESS)
|
||||
return NULL;
|
||||
imxdmac->status = DMA_IN_PROGRESS;
|
||||
|
||||
ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
|
||||
imxdma_progression);
|
||||
if (ret) {
|
||||
dev_err(imxdma->dev, "Failed to setup the DMA handler\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (imxdmac->sg_list)
|
||||
kfree(imxdmac->sg_list);
|
||||
|
||||
imxdmac->sg_list = kcalloc(periods + 1,
|
||||
sizeof(struct scatterlist), GFP_KERNEL);
|
||||
if (!imxdmac->sg_list)
|
||||
return NULL;
|
||||
|
||||
sg_init_table(imxdmac->sg_list, periods);
|
||||
|
||||
for (i = 0; i < periods; i++) {
|
||||
imxdmac->sg_list[i].page_link = 0;
|
||||
imxdmac->sg_list[i].offset = 0;
|
||||
imxdmac->sg_list[i].dma_address = dma_addr;
|
||||
imxdmac->sg_list[i].length = period_len;
|
||||
dma_addr += period_len;
|
||||
}
|
||||
|
||||
/* close the loop */
|
||||
imxdmac->sg_list[periods].offset = 0;
|
||||
imxdmac->sg_list[periods].length = 0;
|
||||
imxdmac->sg_list[periods].page_link =
|
||||
((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
|
||||
|
||||
if (direction == DMA_FROM_DEVICE)
|
||||
dmamode = DMA_MODE_READ;
|
||||
else
|
||||
dmamode = DMA_MODE_WRITE;
|
||||
|
||||
ret = imx_dma_setup_sg(imxdmac->imxdma_channel, imxdmac->sg_list, periods,
|
||||
IMX_DMA_LENGTH_LOOP, imxdmac->per_address, dmamode);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
return &imxdmac->desc;
|
||||
}
|
||||
|
||||
static void imxdma_issue_pending(struct dma_chan *chan)
|
||||
{
|
||||
/*
|
||||
* Nothing to do. We only have a single descriptor
|
||||
*/
|
||||
}
|
||||
|
||||
static int __init imxdma_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct imxdma_engine *imxdma;
|
||||
int ret, i;
|
||||
|
||||
imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL);
|
||||
if (!imxdma)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&imxdma->dma_device.channels);
|
||||
|
||||
/* Initialize channel parameters */
|
||||
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
|
||||
struct imxdma_channel *imxdmac = &imxdma->channel[i];
|
||||
|
||||
imxdmac->imxdma_channel = imx_dma_request_by_prio("dmaengine",
|
||||
DMA_PRIO_MEDIUM);
|
||||
if (imxdmac->channel < 0)
|
||||
goto err_init;
|
||||
|
||||
imx_dma_setup_handlers(imxdmac->imxdma_channel,
|
||||
imxdma_irq_handler, imxdma_err_handler, imxdmac);
|
||||
|
||||
imxdmac->imxdma = imxdma;
|
||||
spin_lock_init(&imxdmac->lock);
|
||||
|
||||
dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
|
||||
dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
|
||||
|
||||
imxdmac->chan.device = &imxdma->dma_device;
|
||||
imxdmac->chan.chan_id = i;
|
||||
imxdmac->channel = i;
|
||||
|
||||
/* Add the channel to the DMAC list */
|
||||
list_add_tail(&imxdmac->chan.device_node, &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;
|
||||
imxdma->dma_device.device_free_chan_resources = imxdma_free_chan_resources;
|
||||
imxdma->dma_device.device_tx_status = imxdma_tx_status;
|
||||
imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
|
||||
imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
|
||||
imxdma->dma_device.device_control = imxdma_control;
|
||||
imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
|
||||
|
||||
platform_set_drvdata(pdev, imxdma);
|
||||
|
||||
ret = dma_async_device_register(&imxdma->dma_device);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register\n");
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_init:
|
||||
while (i-- >= 0) {
|
||||
struct imxdma_channel *imxdmac = &imxdma->channel[i];
|
||||
imx_dma_free(imxdmac->imxdma_channel);
|
||||
}
|
||||
|
||||
kfree(imxdma);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit imxdma_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
dma_async_device_unregister(&imxdma->dma_device);
|
||||
|
||||
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
|
||||
struct imxdma_channel *imxdmac = &imxdma->channel[i];
|
||||
|
||||
imx_dma_free(imxdmac->imxdma_channel);
|
||||
}
|
||||
|
||||
kfree(imxdma);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver imxdma_driver = {
|
||||
.driver = {
|
||||
.name = "imx-dma",
|
||||
},
|
||||
.remove = __exit_p(imxdma_remove),
|
||||
};
|
||||
|
||||
static int __init imxdma_module_init(void)
|
||||
{
|
||||
return platform_driver_probe(&imxdma_driver, imxdma_probe);
|
||||
}
|
||||
subsys_initcall(imxdma_module_init);
|
||||
|
||||
MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("i.MX dma driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large
Load Diff
+390
-86
File diff suppressed because it is too large
Load Diff
@@ -29,11 +29,12 @@
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/pci_ids.h>
|
||||
|
||||
#define INTEL_MID_DMA_DRIVER_VERSION "1.0.5"
|
||||
#define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
|
||||
|
||||
#define REG_BIT0 0x00000001
|
||||
#define REG_BIT8 0x00000100
|
||||
|
||||
#define INT_MASK_WE 0x8
|
||||
#define CLEAR_DONE 0xFFFFEFFF
|
||||
#define UNMASK_INTR_REG(chan_num) \
|
||||
((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
|
||||
#define MASK_INTR_REG(chan_num) (REG_BIT8 << chan_num)
|
||||
@@ -41,6 +42,9 @@
|
||||
#define ENABLE_CHANNEL(chan_num) \
|
||||
((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
|
||||
|
||||
#define DISABLE_CHANNEL(chan_num) \
|
||||
(REG_BIT8 << chan_num)
|
||||
|
||||
#define DESCS_PER_CHANNEL 16
|
||||
/*DMA Registers*/
|
||||
/*registers associated with channel programming*/
|
||||
@@ -50,6 +54,7 @@
|
||||
/*CH X REG = (DMA_CH_SIZE)*CH_NO + REG*/
|
||||
#define SAR 0x00 /* Source Address Register*/
|
||||
#define DAR 0x08 /* Destination Address Register*/
|
||||
#define LLP 0x10 /* Linked List Pointer Register*/
|
||||
#define CTL_LOW 0x18 /* Control Register*/
|
||||
#define CTL_HIGH 0x1C /* Control Register*/
|
||||
#define CFG_LOW 0x40 /* Configuration Register Low*/
|
||||
@@ -112,8 +117,8 @@ union intel_mid_dma_ctl_lo {
|
||||
union intel_mid_dma_ctl_hi {
|
||||
struct {
|
||||
u32 block_ts:12; /*block transfer size*/
|
||||
/*configured by DMAC*/
|
||||
u32 reser:20;
|
||||
u32 done:1; /*Done - updated by DMAC*/
|
||||
u32 reser:19; /*configured by DMAC*/
|
||||
} ctlx;
|
||||
u32 ctl_hi;
|
||||
|
||||
@@ -152,6 +157,7 @@ union intel_mid_dma_cfg_hi {
|
||||
u32 cfg_hi;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct intel_mid_dma_chan - internal mid representation of a DMA channel
|
||||
* @chan: dma_chan strcture represetation for mid chan
|
||||
@@ -166,7 +172,10 @@ union intel_mid_dma_cfg_hi {
|
||||
* @slave: dma slave struture
|
||||
* @descs_allocated: total number of decsiptors allocated
|
||||
* @dma: dma device struture pointer
|
||||
* @busy: bool representing if ch is busy (active txn) or not
|
||||
* @in_use: bool representing if ch is in use or not
|
||||
* @raw_tfr: raw trf interrupt recieved
|
||||
* @raw_block: raw block interrupt recieved
|
||||
*/
|
||||
struct intel_mid_dma_chan {
|
||||
struct dma_chan chan;
|
||||
@@ -178,10 +187,13 @@ struct intel_mid_dma_chan {
|
||||
struct list_head active_list;
|
||||
struct list_head queue;
|
||||
struct list_head free_list;
|
||||
struct intel_mid_dma_slave *slave;
|
||||
unsigned int descs_allocated;
|
||||
struct middma_device *dma;
|
||||
bool busy;
|
||||
bool in_use;
|
||||
u32 raw_tfr;
|
||||
u32 raw_block;
|
||||
struct intel_mid_dma_slave *mid_slave;
|
||||
};
|
||||
|
||||
static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
|
||||
@@ -190,6 +202,10 @@ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
|
||||
return container_of(chan, struct intel_mid_dma_chan, chan);
|
||||
}
|
||||
|
||||
enum intel_mid_dma_state {
|
||||
RUNNING = 0,
|
||||
SUSPENDED,
|
||||
};
|
||||
/**
|
||||
* struct middma_device - internal representation of a DMA device
|
||||
* @pdev: PCI device
|
||||
@@ -205,6 +221,7 @@ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
|
||||
* @max_chan: max number of chs supported (from drv_data)
|
||||
* @block_size: Block size of DMA transfer supported (from drv_data)
|
||||
* @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
|
||||
* @state: dma PM device state
|
||||
*/
|
||||
struct middma_device {
|
||||
struct pci_dev *pdev;
|
||||
@@ -220,6 +237,7 @@ struct middma_device {
|
||||
int max_chan;
|
||||
int block_size;
|
||||
unsigned int pimr_mask;
|
||||
enum intel_mid_dma_state state;
|
||||
};
|
||||
|
||||
static inline struct middma_device *to_middma_device(struct dma_device *common)
|
||||
@@ -238,14 +256,27 @@ struct intel_mid_dma_desc {
|
||||
u32 cfg_lo;
|
||||
u32 ctl_lo;
|
||||
u32 ctl_hi;
|
||||
struct pci_pool *lli_pool;
|
||||
struct intel_mid_dma_lli *lli;
|
||||
dma_addr_t lli_phys;
|
||||
unsigned int lli_length;
|
||||
unsigned int current_lli;
|
||||
dma_addr_t next;
|
||||
enum dma_data_direction dirn;
|
||||
enum dma_status status;
|
||||
enum intel_mid_dma_width width; /*width of DMA txn*/
|
||||
enum dma_slave_buswidth width; /*width of DMA txn*/
|
||||
enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
|
||||
|
||||
};
|
||||
|
||||
struct intel_mid_dma_lli {
|
||||
dma_addr_t sar;
|
||||
dma_addr_t dar;
|
||||
dma_addr_t llp;
|
||||
u32 ctl_lo;
|
||||
u32 ctl_hi;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static inline int test_ch_en(void __iomem *dma, u32 ch_no)
|
||||
{
|
||||
u32 en_reg = ioread32(dma + DMA_CHAN_EN);
|
||||
@@ -257,4 +288,14 @@ static inline struct intel_mid_dma_desc *to_intel_mid_dma_desc
|
||||
{
|
||||
return container_of(txd, struct intel_mid_dma_desc, txd);
|
||||
}
|
||||
|
||||
static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
|
||||
(struct dma_slave_config *slave)
|
||||
{
|
||||
return container_of(slave, struct intel_mid_dma_slave, dma_slave);
|
||||
}
|
||||
|
||||
|
||||
int dma_resume(struct pci_dev *pci);
|
||||
|
||||
#endif /*__INTEL_MID_DMAC_REGS_H__*/
|
||||
|
||||
@@ -162,7 +162,7 @@ static int mv_is_err_intr(u32 intr_cause)
|
||||
|
||||
static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan)
|
||||
{
|
||||
u32 val = (1 << (1 + (chan->idx * 16)));
|
||||
u32 val = ~(1 << (chan->idx * 16));
|
||||
dev_dbg(chan->device->common.dev, "%s, val 0x%08x\n", __func__, val);
|
||||
__raw_writel(val, XOR_INTR_CAUSE(chan));
|
||||
}
|
||||
|
||||
+2
-1
@@ -580,7 +580,6 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
|
||||
|
||||
sh_chan = to_sh_chan(chan);
|
||||
param = chan->private;
|
||||
slave_addr = param->config->addr;
|
||||
|
||||
/* Someone calling slave DMA on a public channel? */
|
||||
if (!param || !sg_len) {
|
||||
@@ -589,6 +588,8 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slave_addr = param->config->addr;
|
||||
|
||||
/*
|
||||
* if (param != NULL), this is a successfully requested slave channel,
|
||||
* therefore param->config != NULL too.
|
||||
|
||||
@@ -1903,6 +1903,18 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
d40_prep_sg(struct dma_chan *chan,
|
||||
struct scatterlist *dst_sg, unsigned int dst_nents,
|
||||
struct scatterlist *src_sg, unsigned int src_nents,
|
||||
unsigned long dma_flags)
|
||||
{
|
||||
if (dst_nents != src_nents)
|
||||
return NULL;
|
||||
|
||||
return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags);
|
||||
}
|
||||
|
||||
static int d40_prep_slave_sg_log(struct d40_desc *d40d,
|
||||
struct d40_chan *d40c,
|
||||
struct scatterlist *sgl,
|
||||
@@ -2325,6 +2337,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
|
||||
base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources;
|
||||
base->dma_slave.device_free_chan_resources = d40_free_chan_resources;
|
||||
base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy;
|
||||
base->dma_slave.device_prep_dma_sg = d40_prep_sg;
|
||||
base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg;
|
||||
base->dma_slave.device_tx_status = d40_tx_status;
|
||||
base->dma_slave.device_issue_pending = d40_issue_pending;
|
||||
@@ -2345,10 +2358,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
|
||||
|
||||
dma_cap_zero(base->dma_memcpy.cap_mask);
|
||||
dma_cap_set(DMA_MEMCPY, base->dma_memcpy.cap_mask);
|
||||
dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
|
||||
|
||||
base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources;
|
||||
base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources;
|
||||
base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy;
|
||||
base->dma_slave.device_prep_dma_sg = d40_prep_sg;
|
||||
base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg;
|
||||
base->dma_memcpy.device_tx_status = d40_tx_status;
|
||||
base->dma_memcpy.device_issue_pending = d40_issue_pending;
|
||||
@@ -2375,10 +2390,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
|
||||
dma_cap_zero(base->dma_both.cap_mask);
|
||||
dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask);
|
||||
dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask);
|
||||
dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
|
||||
|
||||
base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources;
|
||||
base->dma_both.device_free_chan_resources = d40_free_chan_resources;
|
||||
base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy;
|
||||
base->dma_slave.device_prep_dma_sg = d40_prep_sg;
|
||||
base->dma_both.device_prep_slave_sg = d40_prep_slave_sg;
|
||||
base->dma_both.device_tx_status = d40_tx_status;
|
||||
base->dma_both.device_issue_pending = d40_issue_pending;
|
||||
|
||||
Reference in New Issue
Block a user