mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma
Pull slave-dma updates from Vinod Koul: - new driver for BCM2835 used in R-pi - new driver for MOXA ART - dma_get_any_slave_channel API for DT based systems - minor fixes and updates spread acrooss driver [ The fsl-ssi dual fifo mode support addition clashed badly with the other changes to fsl-ssi that came in through the sound merge. I did a very rough cut at fixing up the conflict, but Nicolin Chen (author of both sides) will need to verify and check things ] * 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma: (36 commits) dmaengine: mmp_pdma: fix mismerge dma: pl08x: Export pl08x_filter_id acpi-dma: align documentation with kernel-doc format dma: fix vchan_cookie_complete() debug print DMA: dmatest: extend the "device" module parameter to 32 characters drivers/dma: fix error return code dma: omap: Set debug level to debugging messages dmaengine: fix kernel-doc style typos for few comments dma: tegra: add support for Tegra148/124 dma: dw: use %pad instead of casting dma_addr_t dma: dw: join split up messages dma: dw: fix style of multiline comment dmaengine: k3dma: fix sparse warnings dma: pl330: Use dma_get_slave_channel() in the of xlate callback dma: pl330: Differentiate between submitted and issued descriptors dmaengine: sirf: Add device_slave_caps interface DMA: Freescale: change BWC from 256 bytes to 1024 bytes dmaengine: Add MOXA ART DMA engine driver dmaengine: Add DMA_PRIVATE to BCM2835 driver dma: imx-sdma: Assign a default script number for ROM firmware cases ...
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
* BCM2835 DMA controller
|
||||
|
||||
The BCM2835 DMA controller has 16 channels in total.
|
||||
Only the lower 13 channels have an associated IRQ.
|
||||
Some arbitrary channels are used by the firmware
|
||||
(1,3,6,7 in the current firmware version).
|
||||
The channels 0,2 and 3 have special functionality
|
||||
and should not be used by the driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "brcm,bcm2835-dma".
|
||||
- reg: Should contain DMA registers location and length.
|
||||
- interrupts: Should contain the DMA interrupts associated
|
||||
to the DMA channels in ascending order.
|
||||
- #dma-cells: Must be <1>, the cell in the dmas property of the
|
||||
client device represents the DREQ number.
|
||||
- brcm,dma-channel-mask: Bit mask representing the channels
|
||||
not used by the firmware in ascending order,
|
||||
i.e. first channel corresponds to LSB.
|
||||
|
||||
Example:
|
||||
|
||||
dma: dma@7e007000 {
|
||||
compatible = "brcm,bcm2835-dma";
|
||||
reg = <0x7e007000 0xf00>;
|
||||
interrupts = <1 16>,
|
||||
<1 17>,
|
||||
<1 18>,
|
||||
<1 19>,
|
||||
<1 20>,
|
||||
<1 21>,
|
||||
<1 22>,
|
||||
<1 23>,
|
||||
<1 24>,
|
||||
<1 25>,
|
||||
<1 26>,
|
||||
<1 27>,
|
||||
<1 28>;
|
||||
|
||||
#dma-cells = <1>;
|
||||
brcm,dma-channel-mask = <0x7f35>;
|
||||
};
|
||||
|
||||
DMA clients connected to the BCM2835 DMA controller must use the format
|
||||
described in the dma.txt file, using a two-cell specifier for each channel.
|
||||
|
||||
Example:
|
||||
|
||||
bcm2835_i2s: i2s@7e203000 {
|
||||
compatible = "brcm,bcm2835-i2s";
|
||||
reg = < 0x7e203000 0x20>,
|
||||
< 0x7e101098 0x02>;
|
||||
|
||||
dmas = <&dma 2>,
|
||||
<&dma 3>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
@@ -42,6 +42,7 @@ The full ID of peripheral types can be found below.
|
||||
19 IPU Memory
|
||||
20 ASRC
|
||||
21 ESAI
|
||||
22 SSI Dual FIFO (needs firmware ver >= 2)
|
||||
|
||||
The third cell specifies the transfer priority as below.
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
MOXA ART DMA Controller
|
||||
|
||||
See dma.txt first
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Must be "moxa,moxart-dma"
|
||||
- reg : Should contain registers location and length
|
||||
- interrupts : Should contain an interrupt-specifier for the sole
|
||||
interrupt generated by the device
|
||||
- #dma-cells : Should be 1, a single cell holding a line request number
|
||||
|
||||
Example:
|
||||
|
||||
dma: dma@90500000 {
|
||||
compatible = "moxa,moxart-dma";
|
||||
reg = <0x90500080 0x40>;
|
||||
interrupts = <24 0>;
|
||||
#dma-cells = <1>;
|
||||
};
|
||||
|
||||
|
||||
Clients:
|
||||
|
||||
DMA clients connected to the MOXA ART DMA controller must use the format
|
||||
described in the dma.txt file, using a two-cell specifier for each channel:
|
||||
a phandle plus one integer cells.
|
||||
The two cells in order are:
|
||||
|
||||
1. A phandle pointing to the DMA controller.
|
||||
2. Peripheral identifier for the hardware handshaking interface.
|
||||
|
||||
Example:
|
||||
Use specific request line passing from dma
|
||||
For example, MMC request line is 5
|
||||
|
||||
sdhci: sdhci@98e00000 {
|
||||
compatible = "moxa,moxart-sdhci";
|
||||
reg = <0x98e00000 0x5C>;
|
||||
interrupts = <5 0>;
|
||||
clocks = <&clk_apb>;
|
||||
dmas = <&dma 5>,
|
||||
<&dma 5>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
@@ -306,6 +306,12 @@ config DMA_OMAP
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
|
||||
config DMA_BCM2835
|
||||
tristate "BCM2835 DMA engine support"
|
||||
depends on (ARCH_BCM2835 || MACH_BCM2708)
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
|
||||
config TI_CPPI41
|
||||
tristate "AM33xx CPPI41 DMA support"
|
||||
depends on ARCH_OMAP
|
||||
@@ -336,6 +342,14 @@ config K3_DMA
|
||||
Support the DMA engine for Hisilicon K3 platform
|
||||
devices.
|
||||
|
||||
config MOXART_DMA
|
||||
tristate "MOXART DMA support"
|
||||
depends on ARCH_MOXART
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
help
|
||||
Enable support for the MOXA ART SoC DMA controller.
|
||||
|
||||
config DMA_ENGINE
|
||||
bool
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
|
||||
obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
|
||||
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
|
||||
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
|
||||
obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
|
||||
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
|
||||
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
|
||||
obj-$(CONFIG_TI_CPPI41) += cppi41.o
|
||||
obj-$(CONFIG_K3_DMA) += k3dma.o
|
||||
obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
|
||||
|
||||
+24
-12
@@ -30,11 +30,12 @@ static DEFINE_MUTEX(acpi_dma_lock);
|
||||
* @adev: ACPI device to match with
|
||||
* @adma: struct acpi_dma of the given DMA controller
|
||||
*
|
||||
* Returns 1 on success, 0 when no information is available, or appropriate
|
||||
* errno value on error.
|
||||
*
|
||||
* In order to match a device from DSDT table to the corresponding CSRT device
|
||||
* we use MMIO address and IRQ.
|
||||
*
|
||||
* Return:
|
||||
* 1 on success, 0 when no information is available, or appropriate errno value
|
||||
* on error.
|
||||
*/
|
||||
static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
|
||||
struct acpi_device *adev, struct acpi_dma *adma)
|
||||
@@ -101,7 +102,6 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
|
||||
*
|
||||
* We are using this table to get the request line range of the specific DMA
|
||||
* controller to be used later.
|
||||
*
|
||||
*/
|
||||
static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
|
||||
{
|
||||
@@ -141,10 +141,11 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
|
||||
* @data pointer to controller specific data to be used by
|
||||
* translation function
|
||||
*
|
||||
* Returns 0 on success or appropriate errno value on error.
|
||||
*
|
||||
* Allocated memory should be freed with appropriate acpi_dma_controller_free()
|
||||
* call.
|
||||
*
|
||||
* Return:
|
||||
* 0 on success or appropriate errno value on error.
|
||||
*/
|
||||
int acpi_dma_controller_register(struct device *dev,
|
||||
struct dma_chan *(*acpi_dma_xlate)
|
||||
@@ -188,6 +189,9 @@ EXPORT_SYMBOL_GPL(acpi_dma_controller_register);
|
||||
* @dev: struct device of DMA controller
|
||||
*
|
||||
* Memory allocated by acpi_dma_controller_register() is freed here.
|
||||
*
|
||||
* Return:
|
||||
* 0 on success or appropriate errno value on error.
|
||||
*/
|
||||
int acpi_dma_controller_free(struct device *dev)
|
||||
{
|
||||
@@ -225,6 +229,9 @@ static void devm_acpi_dma_release(struct device *dev, void *res)
|
||||
* Managed acpi_dma_controller_register(). DMA controller registered by this
|
||||
* function are automatically freed on driver detach. See
|
||||
* acpi_dma_controller_register() for more information.
|
||||
*
|
||||
* Return:
|
||||
* 0 on success or appropriate errno value on error.
|
||||
*/
|
||||
int devm_acpi_dma_controller_register(struct device *dev,
|
||||
struct dma_chan *(*acpi_dma_xlate)
|
||||
@@ -267,8 +274,6 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
|
||||
* @adma: struct acpi_dma of DMA controller
|
||||
* @dma_spec: dma specifier to update
|
||||
*
|
||||
* Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
|
||||
*
|
||||
* Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource
|
||||
* Descriptor":
|
||||
* DMA Request Line bits is a platform-relative number uniquely
|
||||
@@ -276,6 +281,9 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
|
||||
* mapping is done in a controller-specific OS driver.
|
||||
* That's why we can safely adjust slave_id when the appropriate controller is
|
||||
* found.
|
||||
*
|
||||
* Return:
|
||||
* 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
|
||||
*/
|
||||
static int acpi_dma_update_dma_spec(struct acpi_dma *adma,
|
||||
struct acpi_dma_spec *dma_spec)
|
||||
@@ -334,7 +342,8 @@ static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
|
||||
* @dev: struct device to get DMA request from
|
||||
* @index: index of FixedDMA descriptor for @dev
|
||||
*
|
||||
* Returns pointer to appropriate dma channel on success or NULL on error.
|
||||
* Return:
|
||||
* Pointer to appropriate dma channel on success or NULL on error.
|
||||
*/
|
||||
struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
|
||||
size_t index)
|
||||
@@ -403,7 +412,8 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
|
||||
* translate the names "tx" and "rx" here based on the most common case where
|
||||
* the first FixedDMA descriptor is TX and second is RX.
|
||||
*
|
||||
* Returns pointer to appropriate dma channel on success or NULL on error.
|
||||
* Return:
|
||||
* Pointer to appropriate dma channel on success or NULL on error.
|
||||
*/
|
||||
struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
|
||||
const char *name)
|
||||
@@ -427,8 +437,10 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
|
||||
* @adma: pointer to ACPI DMA controller data
|
||||
*
|
||||
* A simple translation function for ACPI based devices. Passes &struct
|
||||
* dma_spec to the DMA controller driver provided filter function. Returns
|
||||
* pointer to the channel if found or %NULL otherwise.
|
||||
* dma_spec to the DMA controller driver provided filter function.
|
||||
*
|
||||
* Return:
|
||||
* Pointer to the channel if found or %NULL otherwise.
|
||||
*/
|
||||
struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec,
|
||||
struct acpi_dma *adma)
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
@@ -1771,6 +1772,7 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pl08x_filter_id);
|
||||
|
||||
/*
|
||||
* Just check that the device is there and active
|
||||
@@ -2167,7 +2169,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
/* Register slave channels */
|
||||
ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave,
|
||||
pl08x->pd->num_slave_channels, true);
|
||||
if (ret <= 0) {
|
||||
if (ret < 0) {
|
||||
dev_warn(&pl08x->adev->dev,
|
||||
"%s failed to enumerate slave channels - %d\n",
|
||||
__func__, ret);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -972,8 +972,10 @@ static int cppi41_dma_probe(struct platform_device *pdev)
|
||||
goto err_chans;
|
||||
|
||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!irq)
|
||||
if (!irq) {
|
||||
ret = -EINVAL;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ module_param_string(channel, test_channel, sizeof(test_channel),
|
||||
S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
|
||||
|
||||
static char test_device[20];
|
||||
static char test_device[32];
|
||||
module_param_string(device, test_device, sizeof(test_device),
|
||||
S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
|
||||
@@ -89,7 +89,7 @@ MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)");
|
||||
struct dmatest_params {
|
||||
unsigned int buf_size;
|
||||
char channel[20];
|
||||
char device[20];
|
||||
char device[32];
|
||||
unsigned int threads_per_chan;
|
||||
unsigned int max_channels;
|
||||
unsigned int iterations;
|
||||
|
||||
+18
-17
@@ -218,8 +218,10 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
|
||||
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
|
||||
u32 ctllo;
|
||||
|
||||
/* Software emulation of LLP mode relies on interrupts to continue
|
||||
* multi block transfer. */
|
||||
/*
|
||||
* Software emulation of LLP mode relies on interrupts to continue
|
||||
* multi block transfer.
|
||||
*/
|
||||
ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
|
||||
|
||||
channel_writel(dwc, SAR, desc->lli.sar);
|
||||
@@ -253,8 +255,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
|
||||
&dwc->flags);
|
||||
if (was_soft_llp) {
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
"BUG: Attempted to start new LLP transfer "
|
||||
"inside ongoing one\n");
|
||||
"BUG: Attempted to start new LLP transfer inside ongoing one\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,8 +421,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
|
||||
return;
|
||||
}
|
||||
|
||||
dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
|
||||
(unsigned long long)llp);
|
||||
dev_vdbg(chan2dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp);
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
|
||||
/* Initial residue value */
|
||||
@@ -567,9 +567,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
|
||||
unlikely(status_xfer & dwc->mask)) {
|
||||
int i;
|
||||
|
||||
dev_err(chan2dev(&dwc->chan), "cyclic DMA unexpected %s "
|
||||
"interrupt, stopping DMA transfer\n",
|
||||
status_xfer ? "xfer" : "error");
|
||||
dev_err(chan2dev(&dwc->chan),
|
||||
"cyclic DMA unexpected %s interrupt, stopping DMA transfer\n",
|
||||
status_xfer ? "xfer" : "error");
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
@@ -711,9 +711,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
||||
u32 ctllo;
|
||||
|
||||
dev_vdbg(chan2dev(chan),
|
||||
"%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
|
||||
(unsigned long long)dest, (unsigned long long)src,
|
||||
len, flags);
|
||||
"%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
|
||||
&dest, &src, len, flags);
|
||||
|
||||
if (unlikely(!len)) {
|
||||
dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
|
||||
@@ -1401,9 +1400,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
|
||||
/* Let's make a cyclic list */
|
||||
last->lli.llp = cdesc->desc[0]->txd.phys;
|
||||
|
||||
dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu "
|
||||
"period %zu periods %d\n", (unsigned long long)buf_addr,
|
||||
buf_len, period_len, periods);
|
||||
dev_dbg(chan2dev(&dwc->chan),
|
||||
"cyclic prepared buf %pad len %zu period %zu periods %d\n",
|
||||
&buf_addr, buf_len, period_len, periods);
|
||||
|
||||
cdesc->periods = periods;
|
||||
dwc->cdesc = cdesc;
|
||||
@@ -1603,9 +1602,11 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
|
||||
dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
|
||||
dwc_params);
|
||||
|
||||
/* Decode maximum block size for given channel. The
|
||||
/*
|
||||
* Decode maximum block size for given channel. The
|
||||
* stored 4 bit value represents blocks from 0x00 for 3
|
||||
* up to 0x0a for 4095. */
|
||||
* up to 0x0a for 4095.
|
||||
*/
|
||||
dwc->block_size =
|
||||
(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
|
||||
dwc->nollp =
|
||||
|
||||
+3
-3
@@ -699,8 +699,8 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
|
||||
echan->alloced = true;
|
||||
echan->slot[0] = echan->ch_num;
|
||||
|
||||
dev_info(dev, "allocated channel for %u:%u\n",
|
||||
EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num));
|
||||
dev_dbg(dev, "allocated channel for %u:%u\n",
|
||||
EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num));
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -736,7 +736,7 @@ static void edma_free_chan_resources(struct dma_chan *chan)
|
||||
echan->alloced = false;
|
||||
}
|
||||
|
||||
dev_info(dev, "freeing channel for %u\n", echan->ch_num);
|
||||
dev_dbg(dev, "freeing channel for %u\n", echan->ch_num);
|
||||
}
|
||||
|
||||
/* Send pending descriptor to hardware */
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
* channel is allowed to transfer before the DMA engine pauses
|
||||
* the current channel and switches to the next channel
|
||||
*/
|
||||
#define FSL_DMA_MR_BWC 0x08000000
|
||||
#define FSL_DMA_MR_BWC 0x0A000000
|
||||
|
||||
/* Special MR definition for MPC8349 */
|
||||
#define FSL_DMA_MR_EOTIE 0x00000080
|
||||
|
||||
+22
-1
@@ -323,6 +323,7 @@ struct sdma_engine {
|
||||
struct clk *clk_ipg;
|
||||
struct clk *clk_ahb;
|
||||
spinlock_t channel_0_lock;
|
||||
u32 script_number;
|
||||
struct sdma_script_start_addrs *script_addrs;
|
||||
const struct sdma_driver_data *drvdata;
|
||||
};
|
||||
@@ -724,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
|
||||
per_2_emi = sdma->script_addrs->app_2_mcu_addr;
|
||||
emi_2_per = sdma->script_addrs->mcu_2_app_addr;
|
||||
break;
|
||||
case IMX_DMATYPE_SSI_DUAL:
|
||||
per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
|
||||
emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
|
||||
break;
|
||||
case IMX_DMATYPE_SSI_SP:
|
||||
case IMX_DMATYPE_MMC:
|
||||
case IMX_DMATYPE_SDHC:
|
||||
@@ -1238,6 +1243,7 @@ static void sdma_issue_pending(struct dma_chan *chan)
|
||||
}
|
||||
|
||||
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
|
||||
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38
|
||||
|
||||
static void sdma_add_scripts(struct sdma_engine *sdma,
|
||||
const struct sdma_script_start_addrs *addr)
|
||||
@@ -1246,7 +1252,11 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
|
||||
s32 *saddr_arr = (u32 *)sdma->script_addrs;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
|
||||
/* use the default firmware in ROM if missing external firmware */
|
||||
if (!sdma->script_number)
|
||||
sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
|
||||
|
||||
for (i = 0; i < sdma->script_number; i++)
|
||||
if (addr_arr[i] > 0)
|
||||
saddr_arr[i] = addr_arr[i];
|
||||
}
|
||||
@@ -1272,6 +1282,17 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
|
||||
goto err_firmware;
|
||||
if (header->ram_code_start + header->ram_code_size > fw->size)
|
||||
goto err_firmware;
|
||||
switch (header->version_major) {
|
||||
case 1:
|
||||
sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
|
||||
break;
|
||||
case 2:
|
||||
sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
|
||||
break;
|
||||
default:
|
||||
dev_err(sdma->dev, "unknown firmware version\n");
|
||||
goto err_firmware;
|
||||
}
|
||||
|
||||
addr = (void *)header + header->script_addrs_start;
|
||||
ram_code = (void *)header + header->ram_code_start;
|
||||
|
||||
+2
-2
@@ -477,7 +477,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
|
||||
dma_addr_t addr, src = 0, dst = 0;
|
||||
int num = sglen, i;
|
||||
|
||||
if (sgl == 0)
|
||||
if (sgl == NULL)
|
||||
return NULL;
|
||||
|
||||
for_each_sg(sgl, sg, sglen, i) {
|
||||
@@ -817,7 +817,7 @@ static int k3_dma_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume);
|
||||
static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume);
|
||||
|
||||
static struct platform_driver k3_pdma_driver = {
|
||||
.driver = {
|
||||
|
||||
+98
-93
@@ -5,6 +5,7 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
@@ -32,38 +33,37 @@
|
||||
#define DTADR 0x0208
|
||||
#define DCMD 0x020c
|
||||
|
||||
#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */
|
||||
#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */
|
||||
#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */
|
||||
#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */
|
||||
#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */
|
||||
#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */
|
||||
#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */
|
||||
#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */
|
||||
#define DCSR_RUN BIT(31) /* Run Bit (read / write) */
|
||||
#define DCSR_NODESC BIT(30) /* No-Descriptor Fetch (read / write) */
|
||||
#define DCSR_STOPIRQEN BIT(29) /* Stop Interrupt Enable (read / write) */
|
||||
#define DCSR_REQPEND BIT(8) /* Request Pending (read-only) */
|
||||
#define DCSR_STOPSTATE BIT(3) /* Stop State (read-only) */
|
||||
#define DCSR_ENDINTR BIT(2) /* End Interrupt (read / write) */
|
||||
#define DCSR_STARTINTR BIT(1) /* Start Interrupt (read / write) */
|
||||
#define DCSR_BUSERR BIT(0) /* Bus Error Interrupt (read / write) */
|
||||
|
||||
#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */
|
||||
#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */
|
||||
#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */
|
||||
#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */
|
||||
#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */
|
||||
#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */
|
||||
#define DCSR_EORINTR (1 << 9) /* The end of Receive */
|
||||
#define DCSR_EORIRQEN BIT(28) /* End of Receive Interrupt Enable (R/W) */
|
||||
#define DCSR_EORJMPEN BIT(27) /* Jump to next descriptor on EOR */
|
||||
#define DCSR_EORSTOPEN BIT(26) /* STOP on an EOR */
|
||||
#define DCSR_SETCMPST BIT(25) /* Set Descriptor Compare Status */
|
||||
#define DCSR_CLRCMPST BIT(24) /* Clear Descriptor Compare Status */
|
||||
#define DCSR_CMPST BIT(10) /* The Descriptor Compare Status */
|
||||
#define DCSR_EORINTR BIT(9) /* The end of Receive */
|
||||
|
||||
#define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + \
|
||||
(((n) & 0x3f) << 2))
|
||||
#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */
|
||||
#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */
|
||||
#define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + (((n) & 0x3f) << 2))
|
||||
#define DRCMR_MAPVLD BIT(7) /* Map Valid (read / write) */
|
||||
#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */
|
||||
|
||||
#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */
|
||||
#define DDADR_STOP (1 << 0) /* Stop (read / write) */
|
||||
#define DDADR_STOP BIT(0) /* Stop (read / write) */
|
||||
|
||||
#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */
|
||||
#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */
|
||||
#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */
|
||||
#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */
|
||||
#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */
|
||||
#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */
|
||||
#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */
|
||||
#define DCMD_INCSRCADDR BIT(31) /* Source Address Increment Setting. */
|
||||
#define DCMD_INCTRGADDR BIT(30) /* Target Address Increment Setting. */
|
||||
#define DCMD_FLOWSRC BIT(29) /* Flow Control by the source. */
|
||||
#define DCMD_FLOWTRG BIT(28) /* Flow Control by the target. */
|
||||
#define DCMD_STARTIRQEN BIT(22) /* Start Interrupt Enable */
|
||||
#define DCMD_ENDIRQEN BIT(21) /* End Interrupt Enable */
|
||||
#define DCMD_ENDIAN BIT(18) /* Device Endian-ness. */
|
||||
#define DCMD_BURST8 (1 << 16) /* 8 byte burst */
|
||||
#define DCMD_BURST16 (2 << 16) /* 16 byte burst */
|
||||
#define DCMD_BURST32 (3 << 16) /* 32 byte burst */
|
||||
@@ -132,10 +132,14 @@ struct mmp_pdma_device {
|
||||
spinlock_t phy_lock; /* protect alloc/free phy channels */
|
||||
};
|
||||
|
||||
#define tx_to_mmp_pdma_desc(tx) container_of(tx, struct mmp_pdma_desc_sw, async_tx)
|
||||
#define to_mmp_pdma_desc(lh) container_of(lh, struct mmp_pdma_desc_sw, node)
|
||||
#define to_mmp_pdma_chan(dchan) container_of(dchan, struct mmp_pdma_chan, chan)
|
||||
#define to_mmp_pdma_dev(dmadev) container_of(dmadev, struct mmp_pdma_device, device)
|
||||
#define tx_to_mmp_pdma_desc(tx) \
|
||||
container_of(tx, struct mmp_pdma_desc_sw, async_tx)
|
||||
#define to_mmp_pdma_desc(lh) \
|
||||
container_of(lh, struct mmp_pdma_desc_sw, node)
|
||||
#define to_mmp_pdma_chan(dchan) \
|
||||
container_of(dchan, struct mmp_pdma_chan, chan)
|
||||
#define to_mmp_pdma_dev(dmadev) \
|
||||
container_of(dmadev, struct mmp_pdma_device, device)
|
||||
|
||||
static void set_desc(struct mmp_pdma_phy *phy, dma_addr_t addr)
|
||||
{
|
||||
@@ -162,19 +166,18 @@ static void enable_chan(struct mmp_pdma_phy *phy)
|
||||
writel(dalgn, phy->base + DALGN);
|
||||
|
||||
reg = (phy->idx << 2) + DCSR;
|
||||
writel(readl(phy->base + reg) | DCSR_RUN,
|
||||
phy->base + reg);
|
||||
writel(readl(phy->base + reg) | DCSR_RUN, phy->base + reg);
|
||||
}
|
||||
|
||||
static void disable_chan(struct mmp_pdma_phy *phy)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (phy) {
|
||||
reg = (phy->idx << 2) + DCSR;
|
||||
writel(readl(phy->base + reg) & ~DCSR_RUN,
|
||||
phy->base + reg);
|
||||
}
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
reg = (phy->idx << 2) + DCSR;
|
||||
writel(readl(phy->base + reg) & ~DCSR_RUN, phy->base + reg);
|
||||
}
|
||||
|
||||
static int clear_chan_irq(struct mmp_pdma_phy *phy)
|
||||
@@ -183,26 +186,27 @@ static int clear_chan_irq(struct mmp_pdma_phy *phy)
|
||||
u32 dint = readl(phy->base + DINT);
|
||||
u32 reg = (phy->idx << 2) + DCSR;
|
||||
|
||||
if (dint & BIT(phy->idx)) {
|
||||
/* clear irq */
|
||||
dcsr = readl(phy->base + reg);
|
||||
writel(dcsr, phy->base + reg);
|
||||
if ((dcsr & DCSR_BUSERR) && (phy->vchan))
|
||||
dev_warn(phy->vchan->dev, "DCSR_BUSERR\n");
|
||||
return 0;
|
||||
}
|
||||
return -EAGAIN;
|
||||
if (!(dint & BIT(phy->idx)))
|
||||
return -EAGAIN;
|
||||
|
||||
/* clear irq */
|
||||
dcsr = readl(phy->base + reg);
|
||||
writel(dcsr, phy->base + reg);
|
||||
if ((dcsr & DCSR_BUSERR) && (phy->vchan))
|
||||
dev_warn(phy->vchan->dev, "DCSR_BUSERR\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t mmp_pdma_chan_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct mmp_pdma_phy *phy = dev_id;
|
||||
|
||||
if (clear_chan_irq(phy) == 0) {
|
||||
tasklet_schedule(&phy->vchan->tasklet);
|
||||
return IRQ_HANDLED;
|
||||
} else
|
||||
if (clear_chan_irq(phy) != 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
tasklet_schedule(&phy->vchan->tasklet);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
|
||||
@@ -224,8 +228,8 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
|
||||
|
||||
if (irq_num)
|
||||
return IRQ_HANDLED;
|
||||
else
|
||||
return IRQ_NONE;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* lookup free phy channel as descending priority */
|
||||
@@ -245,9 +249,9 @@ static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan)
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&pdev->phy_lock, flags);
|
||||
for (prio = 0; prio <= (((pdev->dma_channels - 1) & 0xf) >> 2); prio++) {
|
||||
for (prio = 0; prio <= ((pdev->dma_channels - 1) & 0xf) >> 2; prio++) {
|
||||
for (i = 0; i < pdev->dma_channels; i++) {
|
||||
if (prio != ((i & 0xf) >> 2))
|
||||
if (prio != (i & 0xf) >> 2)
|
||||
continue;
|
||||
phy = &pdev->phy[i];
|
||||
if (!phy->vchan) {
|
||||
@@ -389,14 +393,16 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
|
||||
if (chan->desc_pool)
|
||||
return 1;
|
||||
|
||||
chan->desc_pool =
|
||||
dma_pool_create(dev_name(&dchan->dev->device), chan->dev,
|
||||
sizeof(struct mmp_pdma_desc_sw),
|
||||
__alignof__(struct mmp_pdma_desc_sw), 0);
|
||||
chan->desc_pool = dma_pool_create(dev_name(&dchan->dev->device),
|
||||
chan->dev,
|
||||
sizeof(struct mmp_pdma_desc_sw),
|
||||
__alignof__(struct mmp_pdma_desc_sw),
|
||||
0);
|
||||
if (!chan->desc_pool) {
|
||||
dev_err(chan->dev, "unable to allocate descriptor pool\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mmp_pdma_free_phy(chan);
|
||||
chan->idle = true;
|
||||
chan->dev_addr = 0;
|
||||
@@ -404,7 +410,7 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
|
||||
}
|
||||
|
||||
static void mmp_pdma_free_desc_list(struct mmp_pdma_chan *chan,
|
||||
struct list_head *list)
|
||||
struct list_head *list)
|
||||
{
|
||||
struct mmp_pdma_desc_sw *desc, *_desc;
|
||||
|
||||
@@ -434,8 +440,8 @@ static void mmp_pdma_free_chan_resources(struct dma_chan *dchan)
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
mmp_pdma_prep_memcpy(struct dma_chan *dchan,
|
||||
dma_addr_t dma_dst, dma_addr_t dma_src,
|
||||
size_t len, unsigned long flags)
|
||||
dma_addr_t dma_dst, dma_addr_t dma_src,
|
||||
size_t len, unsigned long flags)
|
||||
{
|
||||
struct mmp_pdma_chan *chan;
|
||||
struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new;
|
||||
@@ -515,8 +521,8 @@ fail:
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
|
||||
unsigned int sg_len, enum dma_transfer_direction dir,
|
||||
unsigned long flags, void *context)
|
||||
unsigned int sg_len, enum dma_transfer_direction dir,
|
||||
unsigned long flags, void *context)
|
||||
{
|
||||
struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
|
||||
struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new = NULL;
|
||||
@@ -591,10 +597,11 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic(
|
||||
struct dma_chan *dchan, dma_addr_t buf_addr, size_t len,
|
||||
size_t period_len, enum dma_transfer_direction direction,
|
||||
unsigned long flags, void *context)
|
||||
static struct dma_async_tx_descriptor *
|
||||
mmp_pdma_prep_dma_cyclic(struct dma_chan *dchan,
|
||||
dma_addr_t buf_addr, size_t len, size_t period_len,
|
||||
enum dma_transfer_direction direction,
|
||||
unsigned long flags, void *context)
|
||||
{
|
||||
struct mmp_pdma_chan *chan;
|
||||
struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new;
|
||||
@@ -636,8 +643,8 @@ static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
new->desc.dcmd = chan->dcmd | DCMD_ENDIRQEN |
|
||||
(DCMD_LENGTH & period_len);
|
||||
new->desc.dcmd = (chan->dcmd | DCMD_ENDIRQEN |
|
||||
(DCMD_LENGTH & period_len));
|
||||
new->desc.dsadr = dma_src;
|
||||
new->desc.dtadr = dma_dst;
|
||||
|
||||
@@ -677,12 +684,11 @@ fail:
|
||||
}
|
||||
|
||||
static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
|
||||
unsigned long arg)
|
||||
unsigned long arg)
|
||||
{
|
||||
struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
|
||||
struct dma_slave_config *cfg = (void *)arg;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
u32 maxburst = 0, addr = 0;
|
||||
enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
|
||||
|
||||
@@ -739,11 +745,12 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan,
|
||||
dma_cookie_t cookie, struct dma_tx_state *txstate)
|
||||
dma_cookie_t cookie,
|
||||
struct dma_tx_state *txstate)
|
||||
{
|
||||
return dma_cookie_status(dchan, cookie, txstate);
|
||||
}
|
||||
@@ -845,15 +852,14 @@ static int mmp_pdma_remove(struct platform_device *op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
|
||||
int idx, int irq)
|
||||
static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
|
||||
{
|
||||
struct mmp_pdma_phy *phy = &pdev->phy[idx];
|
||||
struct mmp_pdma_chan *chan;
|
||||
int ret;
|
||||
|
||||
chan = devm_kzalloc(pdev->dev,
|
||||
sizeof(struct mmp_pdma_chan), GFP_KERNEL);
|
||||
chan = devm_kzalloc(pdev->dev, sizeof(struct mmp_pdma_chan),
|
||||
GFP_KERNEL);
|
||||
if (chan == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -861,8 +867,8 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
|
||||
phy->base = pdev->base;
|
||||
|
||||
if (irq) {
|
||||
ret = devm_request_irq(pdev->dev, irq,
|
||||
mmp_pdma_chan_handler, 0, "pdma", phy);
|
||||
ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler, 0,
|
||||
"pdma", phy);
|
||||
if (ret) {
|
||||
dev_err(pdev->dev, "channel request irq fail!\n");
|
||||
return ret;
|
||||
@@ -877,8 +883,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
|
||||
INIT_LIST_HEAD(&chan->chain_running);
|
||||
|
||||
/* register virt channel to dma engine */
|
||||
list_add_tail(&chan->chan.device_node,
|
||||
&pdev->device.channels);
|
||||
list_add_tail(&chan->chan.device_node, &pdev->device.channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -894,14 +899,12 @@ static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec,
|
||||
{
|
||||
struct mmp_pdma_device *d = ofdma->of_dma_data;
|
||||
struct dma_chan *chan;
|
||||
struct mmp_pdma_chan *c;
|
||||
|
||||
chan = dma_get_any_slave_channel(&d->device);
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
c = to_mmp_pdma_chan(chan);
|
||||
c->drcmr = dma_spec->args[0];
|
||||
to_mmp_pdma_chan(chan)->drcmr = dma_spec->args[0];
|
||||
|
||||
return chan;
|
||||
}
|
||||
@@ -918,6 +921,7 @@ static int mmp_pdma_probe(struct platform_device *op)
|
||||
pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
pdev->dev = &op->dev;
|
||||
|
||||
spin_lock_init(&pdev->phy_lock);
|
||||
@@ -929,8 +933,8 @@ static int mmp_pdma_probe(struct platform_device *op)
|
||||
|
||||
of_id = of_match_device(mmp_pdma_dt_ids, pdev->dev);
|
||||
if (of_id)
|
||||
of_property_read_u32(pdev->dev->of_node,
|
||||
"#dma-channels", &dma_channels);
|
||||
of_property_read_u32(pdev->dev->of_node, "#dma-channels",
|
||||
&dma_channels);
|
||||
else if (pdata && pdata->dma_channels)
|
||||
dma_channels = pdata->dma_channels;
|
||||
else
|
||||
@@ -942,8 +946,9 @@ static int mmp_pdma_probe(struct platform_device *op)
|
||||
irq_num++;
|
||||
}
|
||||
|
||||
pdev->phy = devm_kzalloc(pdev->dev,
|
||||
dma_channels * sizeof(struct mmp_pdma_chan), GFP_KERNEL);
|
||||
pdev->phy = devm_kcalloc(pdev->dev,
|
||||
dma_channels, sizeof(struct mmp_pdma_chan),
|
||||
GFP_KERNEL);
|
||||
if (pdev->phy == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -952,8 +957,8 @@ static int mmp_pdma_probe(struct platform_device *op)
|
||||
if (irq_num != dma_channels) {
|
||||
/* all chan share one irq, demux inside */
|
||||
irq = platform_get_irq(op, 0);
|
||||
ret = devm_request_irq(pdev->dev, irq,
|
||||
mmp_pdma_int_handler, 0, "pdma", pdev);
|
||||
ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler, 0,
|
||||
"pdma", pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1029,7 +1034,7 @@ bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param)
|
||||
if (chan->device->dev->driver != &mmp_pdma_driver.driver)
|
||||
return false;
|
||||
|
||||
c->drcmr = *(unsigned int *) param;
|
||||
c->drcmr = *(unsigned int *)param;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1037,6 +1042,6 @@ EXPORT_SYMBOL_GPL(mmp_pdma_filter_fn);
|
||||
|
||||
module_platform_driver(mmp_pdma_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MARVELL MMP Periphera DMA Driver");
|
||||
MODULE_DESCRIPTION("MARVELL MMP Peripheral DMA Driver");
|
||||
MODULE_AUTHOR("Marvell International Ltd.");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
+21
-7
@@ -121,11 +121,13 @@ struct mmp_tdma_chan {
|
||||
int idx;
|
||||
enum mmp_tdma_type type;
|
||||
int irq;
|
||||
unsigned long reg_base;
|
||||
void __iomem *reg_base;
|
||||
|
||||
size_t buf_len;
|
||||
size_t period_len;
|
||||
size_t pos;
|
||||
|
||||
struct gen_pool *pool;
|
||||
};
|
||||
|
||||
#define TDMA_CHANNEL_NUM 2
|
||||
@@ -182,7 +184,7 @@ static void mmp_tdma_pause_chan(struct mmp_tdma_chan *tdmac)
|
||||
|
||||
static int mmp_tdma_config_chan(struct mmp_tdma_chan *tdmac)
|
||||
{
|
||||
unsigned int tdcr;
|
||||
unsigned int tdcr = 0;
|
||||
|
||||
mmp_tdma_disable_chan(tdmac);
|
||||
|
||||
@@ -324,7 +326,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
|
||||
struct gen_pool *gpool;
|
||||
int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
|
||||
|
||||
gpool = sram_get_gpool("asram");
|
||||
gpool = tdmac->pool;
|
||||
if (tdmac->desc_arr)
|
||||
gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
|
||||
size);
|
||||
@@ -374,7 +376,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
|
||||
struct gen_pool *gpool;
|
||||
int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
|
||||
|
||||
gpool = sram_get_gpool("asram");
|
||||
gpool = tdmac->pool;
|
||||
if (!gpool)
|
||||
return NULL;
|
||||
|
||||
@@ -505,7 +507,8 @@ static int mmp_tdma_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
|
||||
int idx, int irq, int type)
|
||||
int idx, int irq,
|
||||
int type, struct gen_pool *pool)
|
||||
{
|
||||
struct mmp_tdma_chan *tdmac;
|
||||
|
||||
@@ -526,7 +529,8 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
|
||||
tdmac->chan.device = &tdev->device;
|
||||
tdmac->idx = idx;
|
||||
tdmac->type = type;
|
||||
tdmac->reg_base = (unsigned long)tdev->base + idx * 4;
|
||||
tdmac->reg_base = tdev->base + idx * 4;
|
||||
tdmac->pool = pool;
|
||||
tdmac->status = DMA_COMPLETE;
|
||||
tdev->tdmac[tdmac->idx] = tdmac;
|
||||
tasklet_init(&tdmac->tasklet, dma_do_tasklet, (unsigned long)tdmac);
|
||||
@@ -553,6 +557,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
|
||||
int i, ret;
|
||||
int irq = 0, irq_num = 0;
|
||||
int chan_num = TDMA_CHANNEL_NUM;
|
||||
struct gen_pool *pool;
|
||||
|
||||
of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
|
||||
if (of_id)
|
||||
@@ -579,6 +584,15 @@ static int mmp_tdma_probe(struct platform_device *pdev)
|
||||
|
||||
INIT_LIST_HEAD(&tdev->device.channels);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
pool = of_get_named_gen_pool(pdev->dev.of_node, "asram", 0);
|
||||
else
|
||||
pool = sram_get_gpool("asram");
|
||||
if (!pool) {
|
||||
dev_err(&pdev->dev, "asram pool not available\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (irq_num != chan_num) {
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(&pdev->dev, irq,
|
||||
@@ -590,7 +604,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
|
||||
/* initialize channel parameters */
|
||||
for (i = 0; i < chan_num; i++) {
|
||||
irq = (irq_num != chan_num) ? 0 : platform_get_irq(pdev, i);
|
||||
ret = mmp_tdma_chan_init(tdev, i, irq, type);
|
||||
ret = mmp_tdma_chan_init(tdev, i, irq, type, pool);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -190,7 +190,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct omap_chan *c = to_omap_dma_chan(chan);
|
||||
|
||||
dev_info(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig);
|
||||
dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig);
|
||||
|
||||
return omap_request_dma(c->dma_sig, "DMA engine",
|
||||
omap_dma_callback, c, &c->dma_ch);
|
||||
@@ -203,7 +203,7 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan)
|
||||
vchan_free_chan_resources(&c->vc);
|
||||
omap_free_dma(c->dma_ch);
|
||||
|
||||
dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig);
|
||||
dev_dbg(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig);
|
||||
}
|
||||
|
||||
static size_t omap_dma_sg_size(struct omap_sg *sg)
|
||||
|
||||
+34
-31
@@ -543,7 +543,9 @@ struct dma_pl330_chan {
|
||||
/* DMA-Engine Channel */
|
||||
struct dma_chan chan;
|
||||
|
||||
/* List of to be xfered descriptors */
|
||||
/* List of submitted descriptors */
|
||||
struct list_head submitted_list;
|
||||
/* List of issued descriptors */
|
||||
struct list_head work_list;
|
||||
/* List of completed descriptors */
|
||||
struct list_head completed_list;
|
||||
@@ -578,12 +580,16 @@ struct dma_pl330_dmac {
|
||||
/* DMA-Engine Device */
|
||||
struct dma_device ddma;
|
||||
|
||||
/* Holds info about sg limitations */
|
||||
struct device_dma_parameters dma_parms;
|
||||
|
||||
/* Pool of descriptors available for the DMAC's channels */
|
||||
struct list_head desc_pool;
|
||||
/* To protect desc_pool manipulation */
|
||||
spinlock_t pool_lock;
|
||||
|
||||
/* Peripheral channels connected to this DMAC */
|
||||
unsigned int num_peripherals;
|
||||
struct dma_pl330_chan *peripherals; /* keep at end */
|
||||
};
|
||||
|
||||
@@ -606,11 +612,6 @@ struct dma_pl330_desc {
|
||||
struct dma_pl330_chan *pchan;
|
||||
};
|
||||
|
||||
struct dma_pl330_filter_args {
|
||||
struct dma_pl330_dmac *pdmac;
|
||||
unsigned int chan_id;
|
||||
};
|
||||
|
||||
static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
|
||||
{
|
||||
if (r && r->xfer_cb)
|
||||
@@ -2298,16 +2299,6 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
|
||||
tasklet_schedule(&pch->task);
|
||||
}
|
||||
|
||||
static bool pl330_dt_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct dma_pl330_filter_args *fargs = param;
|
||||
|
||||
if (chan->device != &fargs->pdmac->ddma)
|
||||
return false;
|
||||
|
||||
return (chan->chan_id == fargs->chan_id);
|
||||
}
|
||||
|
||||
bool pl330_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
u8 *peri_id;
|
||||
@@ -2325,23 +2316,16 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
|
||||
{
|
||||
int count = dma_spec->args_count;
|
||||
struct dma_pl330_dmac *pdmac = ofdma->of_dma_data;
|
||||
struct dma_pl330_filter_args fargs;
|
||||
dma_cap_mask_t cap;
|
||||
|
||||
if (!pdmac)
|
||||
return NULL;
|
||||
unsigned int chan_id;
|
||||
|
||||
if (count != 1)
|
||||
return NULL;
|
||||
|
||||
fargs.pdmac = pdmac;
|
||||
fargs.chan_id = dma_spec->args[0];
|
||||
chan_id = dma_spec->args[0];
|
||||
if (chan_id >= pdmac->num_peripherals)
|
||||
return NULL;
|
||||
|
||||
dma_cap_zero(cap);
|
||||
dma_cap_set(DMA_SLAVE, cap);
|
||||
dma_cap_set(DMA_CYCLIC, cap);
|
||||
|
||||
return dma_request_channel(cap, pl330_dt_filter, &fargs);
|
||||
return dma_get_slave_channel(&pdmac->peripherals[chan_id].chan);
|
||||
}
|
||||
|
||||
static int pl330_alloc_chan_resources(struct dma_chan *chan)
|
||||
@@ -2385,6 +2369,11 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
|
||||
pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
|
||||
|
||||
/* Mark all desc done */
|
||||
list_for_each_entry(desc, &pch->submitted_list, node) {
|
||||
desc->status = FREE;
|
||||
dma_cookie_complete(&desc->txd);
|
||||
}
|
||||
|
||||
list_for_each_entry(desc, &pch->work_list , node) {
|
||||
desc->status = FREE;
|
||||
dma_cookie_complete(&desc->txd);
|
||||
@@ -2395,6 +2384,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
|
||||
dma_cookie_complete(&desc->txd);
|
||||
}
|
||||
|
||||
list_splice_tail_init(&pch->submitted_list, &pdmac->desc_pool);
|
||||
list_splice_tail_init(&pch->work_list, &pdmac->desc_pool);
|
||||
list_splice_tail_init(&pch->completed_list, &pdmac->desc_pool);
|
||||
spin_unlock_irqrestore(&pch->lock, flags);
|
||||
@@ -2453,7 +2443,14 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
||||
|
||||
static void pl330_issue_pending(struct dma_chan *chan)
|
||||
{
|
||||
pl330_tasklet((unsigned long) to_pchan(chan));
|
||||
struct dma_pl330_chan *pch = to_pchan(chan);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pch->lock, flags);
|
||||
list_splice_tail_init(&pch->submitted_list, &pch->work_list);
|
||||
spin_unlock_irqrestore(&pch->lock, flags);
|
||||
|
||||
pl330_tasklet((unsigned long)pch);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2480,11 +2477,11 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
|
||||
dma_cookie_assign(&desc->txd);
|
||||
|
||||
list_move_tail(&desc->node, &pch->work_list);
|
||||
list_move_tail(&desc->node, &pch->submitted_list);
|
||||
}
|
||||
|
||||
cookie = dma_cookie_assign(&last->txd);
|
||||
list_add_tail(&last->node, &pch->work_list);
|
||||
list_add_tail(&last->node, &pch->submitted_list);
|
||||
spin_unlock_irqrestore(&pch->lock, flags);
|
||||
|
||||
return cookie;
|
||||
@@ -2960,6 +2957,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
else
|
||||
num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan);
|
||||
|
||||
pdmac->num_peripherals = num_chan;
|
||||
|
||||
pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
|
||||
if (!pdmac->peripherals) {
|
||||
ret = -ENOMEM;
|
||||
@@ -2974,6 +2973,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
else
|
||||
pch->chan.private = adev->dev.of_node;
|
||||
|
||||
INIT_LIST_HEAD(&pch->submitted_list);
|
||||
INIT_LIST_HEAD(&pch->work_list);
|
||||
INIT_LIST_HEAD(&pch->completed_list);
|
||||
spin_lock_init(&pch->lock);
|
||||
@@ -3021,6 +3021,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
"unable to register DMA to the generic DT DMA helpers\n");
|
||||
}
|
||||
}
|
||||
|
||||
adev->dev.dma_parms = &pdmac->dma_parms;
|
||||
|
||||
/*
|
||||
* This is the limit for transfers with a buswidth of 1, larger
|
||||
* buswidths will have larger limits.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user