mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'dmaengine-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine
Pull dmaengine updates from Vinod Koul:
"Core:
- New devm_of_dma_controller_register() API
- Refactor devm_dma_request_chan() API
New Support:
- Loongson Multi-Channel DMA controller support
- Renesas RZ/{T2H,N2H} support
- Dw CV1800B DMA support
- Switchtec DMA engine driver
U pdates:
- Xilinx AXI dma binding conversion
- Renesas CHCTRL register read updates
- AMD MDB Endpoint and non-LL mode Support
- AXI dma handling of SW and HW cyclic transfers termination
- Intel ioatdma and idxd driver updates"
* tag 'dmaengine-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (62 commits)
dt-bindings: dma: snps,dw-axi-dmac: Add fallback compatible for CV1800B
MAINTAINERS: dmaengine/ti: Remove myself and add Vignesh as maintainer
dmaengine: qcom: Unify user-visible "Qualcomm" name
dt-bindings: dma: qcom,gpi: Document GPI DMA engine for Shikra SoC
dmaengine: qcom: hidma: use sysfs_emit() in sysfs show callbacks
dmaengine: dw-axi-dmac: fix PM for system sleep and channel alloc
dmaengine: dw-axi-dmac: drop redundant DMAC enable in block start
dmaengine: altera-msgdma: Use memcpy_toio for descriptor FIFO writes
dt-bindings: dma: fsl-edma: add dma-channel-mask property description
dmaengine: tegra: Fix burst size calculation
dmaengine: iop32x-adma: Remove a leftover header file
dmaengine: dma-axi-dmac: use DMA pool to manange DMA descriptor
dmaengine: dma-axi-dmac: Drop struct clk from main struct
dmaengine: dma-axi-dmac: Properly free struct axi_dmac_desc
dmaengine: Fix possible use after free
dmaengine: dw-edma: Add spinlock to protect DONE_INT_MASK and ABORT_INT_MASK
dmaengine: dw-edma-pcie: Reject devices without driver data
dmaengine: sh: rz-dmac: Add DMA ACK signal routing support
irqchip/renesas-rzv2h: Add DMA ACK signal routing support
dmaengine: dw-edma: Remove dw_edma_add_irq_mask()
...
This commit is contained in:
@@ -12,6 +12,9 @@ description: |
|
||||
DMAMUX0 and DMAMUX1, specific DMA request source can only be multiplexed
|
||||
by any channel of certain group, DMAMUX0 or DMAMUX1, but not both.
|
||||
|
||||
This binding has an inverted dma-channel-mask definition compared to
|
||||
the common DMA binding for historical reasons.
|
||||
|
||||
maintainers:
|
||||
- Peng Fan <peng.fan@nxp.com>
|
||||
|
||||
@@ -95,6 +98,12 @@ properties:
|
||||
eDMA are implemented in big endian mode, otherwise in little mode.
|
||||
type: boolean
|
||||
|
||||
dma-channel-mask:
|
||||
description: |
|
||||
Bitmask of available DMA channels (inverted definition).
|
||||
Bit semantics: 0 means channel available, 1 means channel unavailable
|
||||
default: 0
|
||||
|
||||
required:
|
||||
- "#dma-cells"
|
||||
- compatible
|
||||
|
||||
@@ -14,17 +14,16 @@ description: |
|
||||
maintainers:
|
||||
- Jon Hunter <jonathanh@nvidia.com>
|
||||
- Rajesh Gumasta <rgumasta@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
- Akhil R <akhilrajeev@nvidia.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: nvidia,tegra186-gpcdma
|
||||
- enum:
|
||||
- nvidia,tegra264-gpcdma
|
||||
- nvidia,tegra186-gpcdma
|
||||
- items:
|
||||
- enum:
|
||||
- nvidia,tegra264-gpcdma
|
||||
- nvidia,tegra234-gpcdma
|
||||
- nvidia,tegra194-gpcdma
|
||||
- const: nvidia,tegra186-gpcdma
|
||||
@@ -51,6 +50,14 @@ properties:
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
iommu-map:
|
||||
description:
|
||||
Maps DMA channel numbers to IOMMU stream IDs. A single entry can map all
|
||||
channels when stream IDs are contiguous. In systems where the channels or
|
||||
stream IDs are not contiguous, multiple entries may be needed.
|
||||
minItems: 1
|
||||
maxItems: 32
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
dma-channel-mask:
|
||||
@@ -60,12 +67,23 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
- "#dma-cells"
|
||||
- iommus
|
||||
- dma-channel-mask
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nvidia,tegra186-gpcdma
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -23,6 +23,8 @@ properties:
|
||||
- qcom,bam-v1.4.0
|
||||
# MSM8916, SDM630
|
||||
- qcom,bam-v1.7.0
|
||||
# Kaanapali
|
||||
- qcom,bam-v2.0.0
|
||||
- items:
|
||||
- enum:
|
||||
# SDM845, SM6115, SM8150, SM8250 and QCM2290
|
||||
@@ -118,4 +120,23 @@ examples:
|
||||
#dma-cells = <1>;
|
||||
qcom,ee = <0>;
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
dma-controller@1dc4000 {
|
||||
compatible = "qcom,bam-v2.0.0";
|
||||
reg = <0x0 0x01dc4000 0x0 0x22000>;
|
||||
interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#dma-cells = <1>;
|
||||
iommus = <&apps_smmu 0xc0 0>, <&apps_smmu 0xc1 0>;
|
||||
qcom,ee = <0>;
|
||||
qcom,num-ees = <4>;
|
||||
num-channels = <20>;
|
||||
qcom,controlled-remotely;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
||||
@@ -24,7 +24,9 @@ properties:
|
||||
- qcom,sm6350-gpi-dma
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,eliza-gpi-dma
|
||||
- qcom,glymur-gpi-dma
|
||||
- qcom,hawi-gpi-dma
|
||||
- qcom,kaanapali-gpi-dma
|
||||
- qcom,milos-gpi-dma
|
||||
- qcom,qcm2290-gpi-dma
|
||||
@@ -35,6 +37,7 @@ properties:
|
||||
- qcom,sc7280-gpi-dma
|
||||
- qcom,sc8280xp-gpi-dma
|
||||
- qcom,sdx75-gpi-dma
|
||||
- qcom,shikra-gpi-dma
|
||||
- qcom,sm6115-gpi-dma
|
||||
- qcom,sm6375-gpi-dma
|
||||
- qcom,sm8350-gpi-dma
|
||||
|
||||
@@ -21,11 +21,12 @@ properties:
|
||||
- enum:
|
||||
- snps,axi-dma-1.01a
|
||||
- intel,kmb-axi-dma
|
||||
- sophgo,cv1800b-axi-dma
|
||||
- starfive,jh7110-axi-dma
|
||||
- starfive,jh8100-axi-dma
|
||||
- items:
|
||||
- const: altr,agilex5-axi-dma
|
||||
- enum:
|
||||
- altr,agilex5-axi-dma
|
||||
- sophgo,cv1800b-axi-dma
|
||||
- const: snps,axi-dma-1.01a
|
||||
|
||||
reg:
|
||||
|
||||
@@ -14,7 +14,9 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: spacemit,k1-pdma
|
||||
enum:
|
||||
- spacemit,k1-pdma
|
||||
- spacemit,k3-pdma
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
+1
-1
@@ -26697,7 +26697,7 @@ F: sound/soc/codecs/tlv320*.*
|
||||
F: sound/soc/codecs/tpa6130a2.*
|
||||
|
||||
TEXAS INSTRUMENTS DMA DRIVERS
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
M: Vignesh Raghavendra <vigneshr@ti.com>
|
||||
L: dmaengine@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
|
||||
|
||||
@@ -496,6 +496,11 @@ static void msgdma_copy_one(struct msgdma_device *mdev,
|
||||
{
|
||||
void __iomem *hw_desc = mdev->desc;
|
||||
|
||||
/* Ensure control is the last field — required for correct FIFO flush ordering */
|
||||
static_assert(offsetof(struct msgdma_extended_desc, control) ==
|
||||
sizeof(struct msgdma_extended_desc) - sizeof(u32),
|
||||
"control must be the last field in msgdma_extended_desc");
|
||||
|
||||
/*
|
||||
* Check if the DESC FIFO it not full. If its full, we need to wait
|
||||
* for at least one entry to become free again
|
||||
@@ -504,17 +509,18 @@ static void msgdma_copy_one(struct msgdma_device *mdev,
|
||||
MSGDMA_CSR_STAT_DESC_BUF_FULL)
|
||||
mdelay(1);
|
||||
|
||||
/* Ensure control is the last field — required for correct FIFO flush ordering */
|
||||
static_assert(offsetof(struct msgdma_extended_desc, control) ==
|
||||
sizeof(struct msgdma_extended_desc) - sizeof(u32),
|
||||
"control must be the last field in msgdma_extended_desc");
|
||||
|
||||
/*
|
||||
* The descriptor needs to get copied into the descriptor FIFO
|
||||
* of the DMA controller. The descriptor will get flushed to the
|
||||
* FIFO, once the last word (control word) is written. Since we
|
||||
* are not 100% sure that memcpy() writes all word in the "correct"
|
||||
* order (address from low to high) on all architectures, we make
|
||||
* sure this control word is written last by single coding it and
|
||||
* adding some write-barriers here.
|
||||
* Copy the descriptor into the descriptor FIFO of the DMA controller,
|
||||
* excluding the control word. The FIFO is flushed and the descriptor
|
||||
* becomes valid once the control word is written last.
|
||||
*/
|
||||
memcpy((void __force *)hw_desc, &desc->hw_desc,
|
||||
sizeof(desc->hw_desc) - sizeof(u32));
|
||||
memcpy_toio(hw_desc, &desc->hw_desc,
|
||||
offsetof(struct msgdma_extended_desc, control));
|
||||
|
||||
/* Write control word last to flush this descriptor into the FIFO */
|
||||
mdev->idle = false;
|
||||
|
||||
+45
-32
@@ -13,6 +13,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@@ -147,6 +148,7 @@ struct axi_dmac_chan {
|
||||
struct virt_dma_chan vchan;
|
||||
|
||||
struct axi_dmac_desc *next_desc;
|
||||
void *pool;
|
||||
struct list_head active_descs;
|
||||
enum dma_transfer_direction direction;
|
||||
|
||||
@@ -170,8 +172,6 @@ struct axi_dmac {
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
|
||||
struct clk *clk;
|
||||
|
||||
struct dma_device dma_dev;
|
||||
struct axi_dmac_chan chan;
|
||||
};
|
||||
@@ -650,11 +650,17 @@ static void axi_dmac_issue_pending(struct dma_chan *c)
|
||||
spin_unlock_irqrestore(&chan->vchan.lock, flags);
|
||||
}
|
||||
|
||||
static void axi_dmac_free_desc(struct axi_dmac_desc *desc)
|
||||
{
|
||||
for (unsigned int i = 0; i < desc->num_sgs; i++)
|
||||
dma_pool_free(desc->chan->pool, desc->sg[i].hw, desc->sg[i].hw_phys);
|
||||
|
||||
kfree(desc);
|
||||
}
|
||||
|
||||
static struct axi_dmac_desc *
|
||||
axi_dmac_alloc_desc(struct axi_dmac_chan *chan, unsigned int num_sgs)
|
||||
{
|
||||
struct axi_dmac *dmac = chan_to_axi_dmac(chan);
|
||||
struct device *dev = dmac->dma_dev.dev;
|
||||
struct axi_dmac_hw_desc *hws;
|
||||
struct axi_dmac_desc *desc;
|
||||
dma_addr_t hw_phys;
|
||||
@@ -666,22 +672,22 @@ axi_dmac_alloc_desc(struct axi_dmac_chan *chan, unsigned int num_sgs)
|
||||
desc->num_sgs = num_sgs;
|
||||
desc->chan = chan;
|
||||
|
||||
hws = dma_alloc_coherent(dev, PAGE_ALIGN(num_sgs * sizeof(*hws)),
|
||||
&hw_phys, GFP_ATOMIC);
|
||||
if (!hws) {
|
||||
kfree(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sgs; i++) {
|
||||
desc->sg[i].hw = &hws[i];
|
||||
desc->sg[i].hw_phys = hw_phys + i * sizeof(*hws);
|
||||
hws = dma_pool_zalloc(chan->pool, GFP_NOWAIT, &hw_phys);
|
||||
if (!hws) {
|
||||
desc->num_sgs = i;
|
||||
axi_dmac_free_desc(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hws[i].id = AXI_DMAC_SG_UNUSED;
|
||||
hws[i].flags = 0;
|
||||
desc->sg[i].hw = hws;
|
||||
desc->sg[i].hw_phys = hw_phys;
|
||||
|
||||
hws->id = AXI_DMAC_SG_UNUSED;
|
||||
|
||||
/* Link hardware descriptors */
|
||||
hws[i].next_sg_addr = hw_phys + (i + 1) * sizeof(*hws);
|
||||
if (i)
|
||||
desc->sg[i - 1].hw->next_sg_addr = hw_phys;
|
||||
}
|
||||
|
||||
/* The last hardware descriptor will trigger an interrupt */
|
||||
@@ -690,18 +696,6 @@ axi_dmac_alloc_desc(struct axi_dmac_chan *chan, unsigned int num_sgs)
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void axi_dmac_free_desc(struct axi_dmac_desc *desc)
|
||||
{
|
||||
struct axi_dmac *dmac = chan_to_axi_dmac(desc->chan);
|
||||
struct device *dev = dmac->dma_dev.dev;
|
||||
struct axi_dmac_hw_desc *hw = desc->sg[0].hw;
|
||||
dma_addr_t hw_phys = desc->sg[0].hw_phys;
|
||||
|
||||
dma_free_coherent(dev, PAGE_ALIGN(desc->num_sgs * sizeof(*hw)),
|
||||
hw, hw_phys);
|
||||
kfree(desc);
|
||||
}
|
||||
|
||||
static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
|
||||
enum dma_transfer_direction direction, dma_addr_t addr,
|
||||
unsigned int num_periods, unsigned int period_len,
|
||||
@@ -769,7 +763,7 @@ axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs,
|
||||
for (i = 0; i < nb; i++) {
|
||||
if (!axi_dmac_check_addr(chan, vecs[i].addr) ||
|
||||
!axi_dmac_check_len(chan, vecs[i].len)) {
|
||||
kfree(desc);
|
||||
axi_dmac_free_desc(desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -935,9 +929,26 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved(
|
||||
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
|
||||
}
|
||||
|
||||
static int axi_dmac_alloc_chan_resources(struct dma_chan *c)
|
||||
{
|
||||
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
|
||||
struct device *dev = c->device->dev;
|
||||
|
||||
chan->pool = dma_pool_create(dev_name(dev), dev,
|
||||
sizeof(struct axi_dmac_hw_desc),
|
||||
__alignof__(struct axi_dmac_hw_desc), 0);
|
||||
if (!chan->pool)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void axi_dmac_free_chan_resources(struct dma_chan *c)
|
||||
{
|
||||
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
|
||||
|
||||
vchan_free_chan_resources(to_virt_chan(c));
|
||||
dma_pool_destroy(chan->pool);
|
||||
}
|
||||
|
||||
static void axi_dmac_desc_free(struct virt_dma_desc *vdesc)
|
||||
@@ -1198,6 +1209,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dma_device *dma_dev;
|
||||
struct axi_dmac *dmac;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
unsigned int version;
|
||||
u32 irq_mask = 0;
|
||||
@@ -1217,9 +1229,9 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(dmac->base))
|
||||
return PTR_ERR(dmac->base);
|
||||
|
||||
dmac->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(dmac->clk))
|
||||
return PTR_ERR(dmac->clk);
|
||||
clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
version = axi_dmac_read(dmac, ADI_AXI_REG_VERSION);
|
||||
|
||||
@@ -1239,6 +1251,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
|
||||
dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
|
||||
dma_cap_set(DMA_CYCLIC, dma_dev->cap_mask);
|
||||
dma_cap_set(DMA_INTERLEAVE, dma_dev->cap_mask);
|
||||
dma_dev->device_alloc_chan_resources = axi_dmac_alloc_chan_resources;
|
||||
dma_dev->device_free_chan_resources = axi_dmac_free_chan_resources;
|
||||
dma_dev->device_tx_status = dma_cookie_status;
|
||||
dma_dev->device_issue_pending = axi_dmac_issue_pending;
|
||||
|
||||
@@ -905,11 +905,12 @@ void dma_release_channel(struct dma_chan *chan)
|
||||
mutex_lock(&dma_list_mutex);
|
||||
WARN_ONCE(chan->client_count != 1,
|
||||
"chan reference count %d != 1\n", chan->client_count);
|
||||
dma_chan_put(chan);
|
||||
/* drop PRIVATE cap enabled by __dma_request_channel() */
|
||||
if (--chan->device->privatecnt == 0)
|
||||
dma_cap_clear(DMA_PRIVATE, chan->device->cap_mask);
|
||||
|
||||
dma_chan_put(chan);
|
||||
|
||||
if (chan->slave) {
|
||||
sysfs_remove_link(&chan->dev->device.kobj, DMA_SLAVE_NAME);
|
||||
sysfs_remove_link(&chan->slave->kobj, chan->name);
|
||||
|
||||
@@ -137,7 +137,7 @@ struct dmatest_params {
|
||||
* @did_init: module has been initialized completely
|
||||
* @last_error: test has faced configuration issues
|
||||
*/
|
||||
static struct dmatest_info {
|
||||
struct dmatest_info {
|
||||
/* Test parameters */
|
||||
struct dmatest_params params;
|
||||
|
||||
@@ -147,7 +147,9 @@ static struct dmatest_info {
|
||||
int last_error;
|
||||
struct mutex lock;
|
||||
bool did_init;
|
||||
} test_info = {
|
||||
};
|
||||
|
||||
static struct dmatest_info test_info = {
|
||||
.channels = LIST_HEAD_INIT(test_info.channels),
|
||||
.lock = __MUTEX_INITIALIZER(test_info.lock),
|
||||
};
|
||||
|
||||
@@ -437,8 +437,6 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
|
||||
return;
|
||||
}
|
||||
|
||||
axi_dma_enable(chan->chip);
|
||||
|
||||
config.dst_multblk_type = DWAXIDMAC_MBLK_TYPE_LL;
|
||||
config.src_multblk_type = DWAXIDMAC_MBLK_TYPE_LL;
|
||||
config.tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC;
|
||||
@@ -518,11 +516,17 @@ static void dw_axi_dma_synchronize(struct dma_chan *dchan)
|
||||
static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
|
||||
{
|
||||
struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(chan->chip->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* ASSERT: channel is idle */
|
||||
if (axi_chan_is_hw_enable(chan)) {
|
||||
dev_err(chan2dev(chan), "%s is non-idle!\n",
|
||||
axi_chan_name(chan));
|
||||
pm_runtime_put(chan->chip->dev);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -533,12 +537,11 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan)
|
||||
64, 0);
|
||||
if (!chan->desc_pool) {
|
||||
dev_err(chan2dev(chan), "No memory for descriptors\n");
|
||||
pm_runtime_put(chan->chip->dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev_vdbg(dchan2dev(dchan), "%s: allocating\n", axi_chan_name(chan));
|
||||
|
||||
pm_runtime_get(chan->chip->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1665,6 +1668,8 @@ static void dw_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dw_axi_dma_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend, axi_dma_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
|
||||
@@ -988,20 +988,12 @@ static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dw_edma_add_irq_mask(u32 *mask, u32 alloc, u16 cnt)
|
||||
{
|
||||
while (*mask * alloc < cnt)
|
||||
(*mask)++;
|
||||
}
|
||||
|
||||
static int dw_edma_irq_request(struct dw_edma *dw,
|
||||
u32 *wr_alloc, u32 *rd_alloc)
|
||||
{
|
||||
struct dw_edma_chip *chip = dw->chip;
|
||||
struct device *dev = dw->chip->dev;
|
||||
struct msi_desc *msi_desc;
|
||||
u32 wr_mask = 1;
|
||||
u32 rd_mask = 1;
|
||||
int i, err = 0;
|
||||
u32 ch_cnt;
|
||||
int irq;
|
||||
@@ -1038,9 +1030,6 @@ static int dw_edma_irq_request(struct dw_edma *dw,
|
||||
dw_edma_dec_irq_alloc(&tmp, rd_alloc, dw->rd_ch_cnt);
|
||||
}
|
||||
|
||||
dw_edma_add_irq_mask(&wr_mask, *wr_alloc, dw->wr_ch_cnt);
|
||||
dw_edma_add_irq_mask(&rd_mask, *rd_alloc, dw->rd_ch_cnt);
|
||||
|
||||
for (i = 0; i < (*wr_alloc + *rd_alloc); i++) {
|
||||
irq = chip->ops->irq_vector(dev, i);
|
||||
err = request_irq(irq,
|
||||
|
||||
@@ -109,7 +109,7 @@ struct dw_edma {
|
||||
|
||||
struct dw_edma_chan *chan;
|
||||
|
||||
raw_spinlock_t lock; /* Only for legacy */
|
||||
raw_spinlock_t lock; /* Protect v0 shared registers */
|
||||
|
||||
struct dw_edma_chip *chip;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
/* AMD MDB (Xilinx) specific defines */
|
||||
#define PCI_DEVICE_ID_XILINX_B054 0xb054
|
||||
#define PCI_DEVICE_ID_XILINX_B00F 0xb00f
|
||||
|
||||
#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6
|
||||
#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20
|
||||
@@ -125,6 +126,19 @@ static const struct dw_edma_pcie_data xilinx_mdb_data = {
|
||||
.rd_ch_cnt = 8,
|
||||
};
|
||||
|
||||
static const struct dw_edma_pcie_data xilinx_cpm6_dma_data = {
|
||||
/* MDB registers location */
|
||||
.rg.bar = BAR_0,
|
||||
.rg.off = SZ_4K, /* 4 Kbytes */
|
||||
.rg.sz = SZ_8K, /* 8 Kbytes */
|
||||
|
||||
/* Other */
|
||||
.mf = EDMA_MF_HDMA_NATIVE,
|
||||
.irqs = 1,
|
||||
.wr_ch_cnt = 8,
|
||||
.rd_ch_cnt = 8,
|
||||
};
|
||||
|
||||
static void dw_edma_set_chan_region_offset(struct dw_edma_pcie_data *pdata,
|
||||
enum pci_barno bar, off_t start_off,
|
||||
off_t ll_off_gap, size_t ll_size,
|
||||
@@ -314,6 +328,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
|
||||
int i, mask;
|
||||
bool non_ll = false;
|
||||
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
|
||||
struct dw_edma_pcie_data *vsec_data __free(kfree) =
|
||||
kmalloc_obj(*vsec_data);
|
||||
if (!vsec_data)
|
||||
@@ -547,6 +564,8 @@ static const struct pci_device_id dw_edma_pcie_id_table[] = {
|
||||
{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
|
||||
{ PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B054),
|
||||
(kernel_ulong_t)&xilinx_mdb_data },
|
||||
{ PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B00F),
|
||||
.driver_data = (kernel_ulong_t)&xilinx_cpm6_dma_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
|
||||
|
||||
@@ -364,6 +364,7 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
|
||||
{
|
||||
struct dw_edma_chan *chan = chunk->chan;
|
||||
struct dw_edma *dw = chan->dw;
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
dw_edma_v0_core_write_chunk(chunk);
|
||||
@@ -408,6 +409,8 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
|
||||
}
|
||||
}
|
||||
/* Interrupt unmask - done, abort */
|
||||
raw_spin_lock_irqsave(&dw->lock, flags);
|
||||
|
||||
tmp = GET_RW_32(dw, chan->dir, int_mask);
|
||||
tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
|
||||
tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
|
||||
@@ -416,6 +419,9 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
|
||||
tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
|
||||
tmp |= FIELD_PREP(EDMA_V0_LINKED_LIST_ERR_MASK, BIT(chan->id));
|
||||
SET_RW_32(dw, chan->dir, linked_list_err_en, tmp);
|
||||
|
||||
raw_spin_unlock_irqrestore(&dw->lock, flags);
|
||||
|
||||
/* Channel control */
|
||||
SET_CH_32(dw, chan->dir, chan->id, ch_control1,
|
||||
(DW_EDMA_V0_CCS | DW_EDMA_V0_LLE));
|
||||
|
||||
@@ -1587,18 +1587,11 @@ static const struct of_device_id ep93xx_dma_of_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_dma_of_ids);
|
||||
|
||||
static const struct platform_device_id ep93xx_dma_driver_ids[] = {
|
||||
{ "ep93xx-dma-m2p", 0 },
|
||||
{ "ep93xx-dma-m2m", 1 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver ep93xx_dma_driver = {
|
||||
.driver = {
|
||||
.name = "ep93xx-dma",
|
||||
.of_match_table = ep93xx_dma_of_ids,
|
||||
},
|
||||
.id_table = ep93xx_dma_driver_ids,
|
||||
.probe = ep93xx_dma_probe,
|
||||
};
|
||||
|
||||
|
||||
@@ -1037,6 +1037,7 @@ static const struct pci_device_id hisi_dma_pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, 0xa122) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, hisi_dma_pci_tbl);
|
||||
|
||||
static struct pci_driver hisi_dma_pci_driver = {
|
||||
.name = "hisi_dma",
|
||||
@@ -1050,4 +1051,3 @@ MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>");
|
||||
MODULE_AUTHOR("Zhenfa Qiu <qiuzhenfa@hisilicon.com>");
|
||||
MODULE_DESCRIPTION("HiSilicon Kunpeng DMA controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DEVICE_TABLE(pci, hisi_dma_pci_tbl);
|
||||
|
||||
@@ -2364,7 +2364,9 @@ static int sdma_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to register controller\n");
|
||||
|
||||
spba_bus = of_find_compatible_node(NULL, NULL, "fsl,spba-bus");
|
||||
struct device_node *sdma_parent_np __free(device_node) = of_get_parent(np);
|
||||
|
||||
spba_bus = of_get_compatible_child(sdma_parent_np, "fsl,spba-bus");
|
||||
ret = of_address_to_resource(spba_bus, 0, &spba_res);
|
||||
if (!ret) {
|
||||
sdma->spba_start_addr = spba_res.start;
|
||||
|
||||
+34
-3
@@ -51,7 +51,10 @@
|
||||
#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_BASE 0x0100
|
||||
#define DRCMR_EXT_BASE_K3 0x1000
|
||||
#define DRCMR_EXT_BASE_DEFAULT 0x1100
|
||||
#define DRCMR_REQ_LIMIT 64
|
||||
#define DRCMR_MAPVLD BIT(7) /* Map Valid (read / write) */
|
||||
#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */
|
||||
|
||||
@@ -154,6 +157,7 @@ struct mmp_pdma_phy {
|
||||
* @run_bits: Control bits in DCSR register for channel start/stop
|
||||
* @dma_width: DMA addressing width in bits (32 or 64). Determines the
|
||||
* DMA mask capability of the controller hardware.
|
||||
* @drcmr_ext_base: Base DRCMR address for extended requests
|
||||
*/
|
||||
struct mmp_pdma_ops {
|
||||
/* Hardware Register Operations */
|
||||
@@ -174,6 +178,7 @@ struct mmp_pdma_ops {
|
||||
/* Controller Configuration */
|
||||
u32 run_bits;
|
||||
u32 dma_width;
|
||||
u32 drcmr_ext_base;
|
||||
};
|
||||
|
||||
struct mmp_pdma_device {
|
||||
@@ -195,6 +200,13 @@ struct mmp_pdma_device {
|
||||
#define to_mmp_pdma_dev(dmadev) \
|
||||
container_of(dmadev, struct mmp_pdma_device, device)
|
||||
|
||||
static u32 mmp_pdma_get_drcmr(struct mmp_pdma_device *pdev, u32 drcmr)
|
||||
{
|
||||
if (drcmr < DRCMR_REQ_LIMIT)
|
||||
return DRCMR_BASE + (drcmr << 2);
|
||||
return pdev->ops->drcmr_ext_base + ((drcmr - DRCMR_REQ_LIMIT) << 2);
|
||||
}
|
||||
|
||||
/* For 32-bit PDMA */
|
||||
static void write_next_addr_32(struct mmp_pdma_phy *phy, dma_addr_t addr)
|
||||
{
|
||||
@@ -301,7 +313,7 @@ static void enable_chan(struct mmp_pdma_phy *phy)
|
||||
|
||||
pdev = to_mmp_pdma_dev(phy->vchan->chan.device);
|
||||
|
||||
reg = DRCMR(phy->vchan->drcmr);
|
||||
reg = mmp_pdma_get_drcmr(pdev, phy->vchan->drcmr);
|
||||
writel(DRCMR_MAPVLD | phy->idx, phy->base + reg);
|
||||
|
||||
dalgn = readl(phy->base + DALGN);
|
||||
@@ -437,7 +449,7 @@ static void mmp_pdma_free_phy(struct mmp_pdma_chan *pchan)
|
||||
return;
|
||||
|
||||
/* clear the channel mapping in DRCMR */
|
||||
reg = DRCMR(pchan->drcmr);
|
||||
reg = mmp_pdma_get_drcmr(pdev, pchan->drcmr);
|
||||
writel(0, pchan->phy->base + reg);
|
||||
|
||||
spin_lock_irqsave(&pdev->phy_lock, flags);
|
||||
@@ -1179,6 +1191,7 @@ static const struct mmp_pdma_ops marvell_pdma_v1_ops = {
|
||||
.get_desc_dst_addr = get_desc_dst_addr_32,
|
||||
.run_bits = (DCSR_RUN),
|
||||
.dma_width = 32,
|
||||
.drcmr_ext_base = DRCMR_EXT_BASE_DEFAULT,
|
||||
};
|
||||
|
||||
static const struct mmp_pdma_ops spacemit_k1_pdma_ops = {
|
||||
@@ -1192,6 +1205,21 @@ static const struct mmp_pdma_ops spacemit_k1_pdma_ops = {
|
||||
.get_desc_dst_addr = get_desc_dst_addr_64,
|
||||
.run_bits = (DCSR_RUN | DCSR_LPAEEN),
|
||||
.dma_width = 64,
|
||||
.drcmr_ext_base = DRCMR_EXT_BASE_DEFAULT,
|
||||
};
|
||||
|
||||
static const struct mmp_pdma_ops spacemit_k3_pdma_ops = {
|
||||
.write_next_addr = write_next_addr_64,
|
||||
.read_src_addr = read_src_addr_64,
|
||||
.read_dst_addr = read_dst_addr_64,
|
||||
.set_desc_next_addr = set_desc_next_addr_64,
|
||||
.set_desc_src_addr = set_desc_src_addr_64,
|
||||
.set_desc_dst_addr = set_desc_dst_addr_64,
|
||||
.get_desc_src_addr = get_desc_src_addr_64,
|
||||
.get_desc_dst_addr = get_desc_dst_addr_64,
|
||||
.run_bits = (DCSR_RUN | DCSR_LPAEEN | DCSR_EORIRQEN | DCSR_EORSTOPEN),
|
||||
.dma_width = 64,
|
||||
.drcmr_ext_base = DRCMR_EXT_BASE_K3,
|
||||
};
|
||||
|
||||
static const struct of_device_id mmp_pdma_dt_ids[] = {
|
||||
@@ -1201,6 +1229,9 @@ static const struct of_device_id mmp_pdma_dt_ids[] = {
|
||||
}, {
|
||||
.compatible = "spacemit,k1-pdma",
|
||||
.data = &spacemit_k1_pdma_ops
|
||||
}, {
|
||||
.compatible = "spacemit,k3-pdma",
|
||||
.data = &spacemit_k3_pdma_ops
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user