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:
Linus Torvalds
2026-06-23 15:51:14 -07:00
36 changed files with 1408 additions and 938 deletions
@@ -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
View File
@@ -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
+15 -9
View File
@@ -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
View File
@@ -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;
+2 -1
View File
@@ -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);
+4 -2
View File
@@ -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)
};
-11
View File
@@ -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,
+1 -1
View File
@@ -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;
+19
View File
@@ -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);
+6
View File
@@ -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));
-7
View File
@@ -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,
};
+1 -1
View File
@@ -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);
+3 -1
View File
@@ -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
View File
@@ -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