diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-23 15:51:14 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-23 15:51:14 -0700 |
| commit | 558ef39aeb9a089a6be9dda8413b0b9d42e843ea (patch) | |
| tree | e1e74a1737d7599ad4f6954e1b0b171df18cc5c9 /drivers | |
| parent | 62cf248de32f061d99cf7cd1675419d739031c5e (diff) | |
| parent | 7524fe142b5a772f8421aeee2132cf7e21a00103 (diff) | |
| download | lwn-558ef39aeb9a089a6be9dda8413b0b9d42e843ea.tar.gz lwn-558ef39aeb9a089a6be9dda8413b0b9d42e843ea.zip | |
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()
...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/dma/altera-msgdma.c | 24 | ||||
| -rw-r--r-- | drivers/dma/dma-axi-dmac.c | 77 | ||||
| -rw-r--r-- | drivers/dma/dmaengine.c | 3 | ||||
| -rw-r--r-- | drivers/dma/dmatest.c | 6 | ||||
| -rw-r--r-- | drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 13 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-core.c | 11 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-core.h | 2 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-pcie.c | 19 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-v0-core.c | 6 | ||||
| -rw-r--r-- | drivers/dma/ep93xx_dma.c | 7 | ||||
| -rw-r--r-- | drivers/dma/hisi_dma.c | 2 | ||||
| -rw-r--r-- | drivers/dma/imx-sdma.c | 4 | ||||
| -rw-r--r-- | drivers/dma/mmp_pdma.c | 37 | ||||
| -rw-r--r-- | drivers/dma/nbpfaxi.c | 15 | ||||
| -rw-r--r-- | drivers/dma/pch_dma.c | 2 | ||||
| -rw-r--r-- | drivers/dma/qcom/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/dma/qcom/bam_dma.c | 30 | ||||
| -rw-r--r-- | drivers/dma/qcom/gpi.c | 1 | ||||
| -rw-r--r-- | drivers/dma/qcom/hidma.c | 6 | ||||
| -rw-r--r-- | drivers/dma/qcom/hidma_mgmt_sys.c | 19 | ||||
| -rw-r--r-- | drivers/dma/sh/rz-dmac.c | 892 | ||||
| -rw-r--r-- | drivers/dma/ste_dma40.c | 14 | ||||
| -rw-r--r-- | drivers/dma/tegra186-gpc-dma.c | 436 | ||||
| -rw-r--r-- | drivers/dma/tegra210-adma.c | 63 | ||||
| -rw-r--r-- | drivers/irqchip/irq-renesas-rzv2h.c | 40 |
25 files changed, 1189 insertions, 548 deletions
diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c index b46999c81df0..e23e5b441a24 100644 --- a/drivers/dma/altera-msgdma.c +++ b/drivers/dma/altera-msgdma.c @@ -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; diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 45c2c8e4bc45..d47ff27e1408 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -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; diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 405bd2fbb4a3..9049171df857 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -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); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index df38681a1ff4..2ae3469397f3 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -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), }; diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 4d53f077e9d2..bcefaff03b5c 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -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) }; diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index c2feb3adc79f..89a4c498a17b 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -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, diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h index 902574b1ba86..6474cacf7195 100644 --- a/drivers/dma/dw-edma/dw-edma-core.h +++ b/drivers/dma/dw-edma/dw-edma-core.h @@ -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; diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c index 0b30ce138503..791c46e8ae4c 100644 --- a/drivers/dma/dw-edma/dw-edma-pcie.c +++ b/drivers/dma/dw-edma/dw-edma-pcie.c @@ -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); diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c index 69e8279adec8..cfdd6463252e 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-core.c +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c @@ -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)); diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 8eceb96d058c..a3395cfcf5dd 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -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, }; diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c index 32a0e95c6a20..28bf818f9aa6 100644 --- a/drivers/dma/hisi_dma.c +++ b/drivers/dma/hisi_dma.c @@ -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); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 3d527883776b..36368835a845 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -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; diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index d12e729ee12c..386e85cd4882 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -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[] = { @@ -1202,6 +1230,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 */ } }; diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 334425faac00..05d7321629cc 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -1486,20 +1486,6 @@ static void nbpf_remove(struct platform_device *pdev) clk_disable_unprepare(nbpf->clk); } -static const struct platform_device_id nbpf_ids[] = { - {"nbpfaxi64dmac1b4", (kernel_ulong_t)&nbpf_cfg[NBPF1B4]}, - {"nbpfaxi64dmac1b8", (kernel_ulong_t)&nbpf_cfg[NBPF1B8]}, - {"nbpfaxi64dmac1b16", (kernel_ulong_t)&nbpf_cfg[NBPF1B16]}, - {"nbpfaxi64dmac4b4", (kernel_ulong_t)&nbpf_cfg[NBPF4B4]}, - {"nbpfaxi64dmac4b8", (kernel_ulong_t)&nbpf_cfg[NBPF4B8]}, - {"nbpfaxi64dmac4b16", (kernel_ulong_t)&nbpf_cfg[NBPF4B16]}, - {"nbpfaxi64dmac8b4", (kernel_ulong_t)&nbpf_cfg[NBPF8B4]}, - {"nbpfaxi64dmac8b8", (kernel_ulong_t)&nbpf_cfg[NBPF8B8]}, - {"nbpfaxi64dmac8b16", (kernel_ulong_t)&nbpf_cfg[NBPF8B16]}, - {}, -}; -MODULE_DEVICE_TABLE(platform, nbpf_ids); - static int nbpf_runtime_suspend(struct device *dev) { struct nbpf_device *nbpf = dev_get_drvdata(dev); @@ -1523,7 +1509,6 @@ static struct platform_driver nbpf_driver = { .of_match_table = nbpf_match, .pm = pm_ptr(&nbpf_pm_ops), }, - .id_table = nbpf_ids, .probe = nbpf_probe, .remove = nbpf_remove, }; diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index e9fbfd5a3d51..bf805f1024f6 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -970,6 +970,7 @@ static const struct pci_device_id pch_dma_id_table[] = { { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA2_4CH), 4}, /* SPI */ { 0, }, }; +MODULE_DEVICE_TABLE(pci, pch_dma_id_table); static SIMPLE_DEV_PM_OPS(pch_dma_pm_ops, pch_dma_suspend, pch_dma_resume); @@ -987,4 +988,3 @@ MODULE_DESCRIPTION("Intel EG20T PCH / LAPIS Semicon ML7213/ML7223/ML7831 IOH " "DMA controller driver"); MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(pci, pch_dma_id_table); diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig index ace75d7b835a..c71b0b5d536b 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig @@ -11,7 +11,7 @@ config QCOM_ADM and on-chip peripheral devices. config QCOM_BAM_DMA - tristate "QCOM BAM DMA support" + tristate "Qualcomm BAM DMA support" depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) select DMA_ENGINE select DMA_VIRTUAL_CHANNELS @@ -20,7 +20,7 @@ config QCOM_BAM_DMA provides DMA capabilities for a variety of on-chip devices. config QCOM_GPI_DMA - tristate "Qualcomm Technologies GPI DMA support" + tristate "Qualcomm GPI DMA support" depends on ARCH_QCOM select DMA_ENGINE select DMA_VIRTUAL_CHANNELS @@ -32,7 +32,7 @@ config QCOM_GPI_DMA transfer data between DDR and peripheral. config QCOM_HIDMA_MGMT - tristate "Qualcomm Technologies HIDMA Management support" + tristate "Qualcomm HIDMA Management support" depends on HAS_IOMEM select DMA_ENGINE help @@ -44,7 +44,7 @@ config QCOM_HIDMA_MGMT host would run the QCOM_HIDMA_MGMT management driver. config QCOM_HIDMA - tristate "Qualcomm Technologies HIDMA Channel support" + tristate "Qualcomm HIDMA Channel support" depends on HAS_IOMEM select DMA_ENGINE help diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 19116295f832..1bb26af0405f 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -199,6 +199,35 @@ static const struct reg_offset_data bam_v1_7_reg_info[] = { [BAM_P_FIFO_SIZES] = { 0x13820, 0x00, 0x1000, 0x00 }, }; +static const struct reg_offset_data bam_v2_0_reg_info[] = { + [BAM_CTRL] = { 0x0000, 0x00, 0x00, 0x00 }, + [BAM_REVISION] = { 0x1000, 0x00, 0x00, 0x00 }, + [BAM_NUM_PIPES] = { 0x1008, 0x00, 0x00, 0x00 }, + [BAM_DESC_CNT_TRSHLD] = { 0x0008, 0x00, 0x00, 0x00 }, + [BAM_IRQ_SRCS] = { 0x3010, 0x00, 0x00, 0x00 }, + [BAM_IRQ_SRCS_MSK] = { 0x3014, 0x00, 0x00, 0x00 }, + [BAM_IRQ_SRCS_UNMASKED] = { 0x3018, 0x00, 0x00, 0x00 }, + [BAM_IRQ_STTS] = { 0x0014, 0x00, 0x00, 0x00 }, + [BAM_IRQ_CLR] = { 0x0018, 0x00, 0x00, 0x00 }, + [BAM_IRQ_EN] = { 0x001C, 0x00, 0x00, 0x00 }, + [BAM_CNFG_BITS] = { 0x007C, 0x00, 0x00, 0x00 }, + [BAM_IRQ_SRCS_EE] = { 0x3000, 0x00, 0x00, 0x1000 }, + [BAM_IRQ_SRCS_MSK_EE] = { 0x3004, 0x00, 0x00, 0x1000 }, + [BAM_P_CTRL] = { 0xC000, 0x1000, 0x00, 0x00 }, + [BAM_P_RST] = { 0xC004, 0x1000, 0x00, 0x00 }, + [BAM_P_HALT] = { 0xC008, 0x1000, 0x00, 0x00 }, + [BAM_P_IRQ_STTS] = { 0xC010, 0x1000, 0x00, 0x00 }, + [BAM_P_IRQ_CLR] = { 0xC014, 0x1000, 0x00, 0x00 }, + [BAM_P_IRQ_EN] = { 0xC018, 0x1000, 0x00, 0x00 }, + [BAM_P_EVNT_DEST_ADDR] = { 0xC82C, 0x00, 0x1000, 0x00 }, + [BAM_P_EVNT_REG] = { 0xC818, 0x00, 0x1000, 0x00 }, + [BAM_P_SW_OFSTS] = { 0xC800, 0x00, 0x1000, 0x00 }, + [BAM_P_DATA_FIFO_ADDR] = { 0xC824, 0x00, 0x1000, 0x00 }, + [BAM_P_DESC_FIFO_ADDR] = { 0xC81C, 0x00, 0x1000, 0x00 }, + [BAM_P_EVNT_GEN_TRSHLD] = { 0xC828, 0x00, 0x1000, 0x00 }, + [BAM_P_FIFO_SIZES] = { 0xC820, 0x00, 0x1000, 0x00 }, +}; + /* BAM CTRL */ #define BAM_SW_RST BIT(0) #define BAM_EN BIT(1) @@ -1208,6 +1237,7 @@ static const struct of_device_id bam_of_match[] = { { .compatible = "qcom,bam-v1.3.0", .data = &bam_v1_3_reg_info }, { .compatible = "qcom,bam-v1.4.0", .data = &bam_v1_4_reg_info }, { .compatible = "qcom,bam-v1.7.0", .data = &bam_v1_7_reg_info }, + { .compatible = "qcom,bam-v2.0.0", .data = &bam_v2_0_reg_info }, {} }; diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index c9a6f610ffd9..a5055a6273af 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -2260,6 +2260,7 @@ static int gpi_probe(struct platform_device *pdev) /* clear and Set capabilities */ dma_cap_zero(gpi_dev->dma_device.cap_mask); dma_cap_set(DMA_SLAVE, gpi_dev->dma_device.cap_mask); + dma_cap_set(DMA_PRIVATE, gpi_dev->dma_device.cap_mask); /* configure dmaengine apis */ gpi_dev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 5a8dca8db5ce..7a7f302a9699 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -624,12 +624,10 @@ static ssize_t hidma_show_values(struct device *dev, { struct hidma_dev *mdev = dev_get_drvdata(dev); - buf[0] = 0; - if (strcmp(attr->attr.name, "chid") == 0) - sprintf(buf, "%d\n", mdev->chidx); + return sysfs_emit(buf, "%d\n", mdev->chidx); - return strlen(buf); + return 0; } static inline void hidma_sysfs_uninit(struct hidma_dev *dev) diff --git a/drivers/dma/qcom/hidma_mgmt_sys.c b/drivers/dma/qcom/hidma_mgmt_sys.c index 930eae0a6257..9672ef9ee8fc 100644 --- a/drivers/dma/qcom/hidma_mgmt_sys.c +++ b/drivers/dma/qcom/hidma_mgmt_sys.c @@ -102,15 +102,12 @@ static ssize_t show_values(struct device *dev, struct device_attribute *attr, struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev); unsigned int i; - buf[0] = 0; - for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) { - if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) { - sprintf(buf, "%d\n", hidma_mgmt_files[i].get(mdev)); - break; - } + if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) + return sysfs_emit(buf, "%d\n", + hidma_mgmt_files[i].get(mdev)); } - return strlen(buf); + return 0; } static ssize_t set_values(struct device *dev, struct device_attribute *attr, @@ -143,15 +140,15 @@ static ssize_t show_values_channel(struct kobject *kobj, struct hidma_chan_attr *chattr; struct hidma_mgmt_dev *mdev; - buf[0] = 0; chattr = container_of(attr, struct hidma_chan_attr, attr); mdev = chattr->mdev; + if (strcmp(attr->attr.name, "priority") == 0) - sprintf(buf, "%d\n", mdev->priority[chattr->index]); + return sysfs_emit(buf, "%d\n", mdev->priority[chattr->index]); else if (strcmp(attr->attr.name, "weight") == 0) - sprintf(buf, "%d\n", mdev->weight[chattr->index]); + return sysfs_emit(buf, "%d\n", mdev->weight[chattr->index]); - return strlen(buf); + return 0; } static ssize_t set_values_channel(struct kobject *kobj, diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 625ff29024de..ca76f1bb45c4 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -18,6 +18,7 @@ #include <linux/irqchip/irq-renesas-rzv2h.h> #include <linux/irqchip/irq-renesas-rzt2h.h> #include <linux/list.h> +#include <linux/lockdep.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_dma.h> @@ -34,6 +35,7 @@ enum rz_dmac_prep_type { RZ_DMAC_DESC_MEMCPY, RZ_DMAC_DESC_SLAVE_SG, + RZ_DMAC_DESC_CYCLIC, }; struct rz_lmdesc { @@ -58,10 +60,23 @@ struct rz_dmac_desc { /* For slave sg */ struct scatterlist *sg; unsigned int sgcount; + struct rz_lmdesc *start_lmdesc; }; #define to_rz_dmac_desc(d) container_of(d, struct rz_dmac_desc, vd) +/** + * enum rz_dmac_chan_status: RZ DMAC channel status + * @RZ_DMAC_CHAN_STATUS_PAUSED: Channel is paused though DMA engine callbacks + * @RZ_DMAC_CHAN_STATUS_CYCLIC: Channel is cyclic + * @RZ_DMAC_CHAN_STATUS_PAUSED_INTERNAL: Channel is paused through driver internal logic + */ +enum rz_dmac_chan_status { + RZ_DMAC_CHAN_STATUS_PAUSED, + RZ_DMAC_CHAN_STATUS_CYCLIC, + RZ_DMAC_CHAN_STATUS_PAUSED_INTERNAL, +}; + struct rz_dmac_chan { struct virt_dma_chan vc; void __iomem *ch_base; @@ -73,13 +88,18 @@ struct rz_dmac_chan { dma_addr_t src_per_address; dma_addr_t dst_per_address; + unsigned long status; + u32 chcfg; u32 chctrl; int mid_rid; + int dmac_ack; + + struct { + u32 nxla; + } pm_state; struct list_head ld_free; - struct list_head ld_queue; - struct list_head ld_active; struct { struct rz_lmdesc *base; @@ -99,6 +119,9 @@ struct rz_dmac_icu { struct rz_dmac_info { void (*icu_register_dma_req)(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel, u16 req_no); + void (*icu_register_dma_ack)(struct platform_device *icu_dev, + u8 dmac_index, u8 dmac_channel, u16 ack_no); + u16 default_dma_ack_no; u16 default_dma_req_no; }; @@ -181,6 +204,8 @@ struct rz_dmac { /* LINK MODE DESCRIPTOR */ #define HEADER_LV BIT(0) +#define HEADER_LE BIT(1) +#define HEADER_WBD BIT(2) #define RZ_DMAC_MAX_CHAN_DESCRIPTORS 16 #define RZ_DMAC_MAX_CHANNELS 16 @@ -259,6 +284,12 @@ static void rz_lmdesc_setup(struct rz_dmac_chan *channel, * Descriptors preparation */ +static u32 rz_dmac_lmdesc_addr(struct rz_dmac_chan *channel, struct rz_lmdesc *lmdesc) +{ + return channel->lmdesc.base_dma + + (sizeof(struct rz_lmdesc) * (lmdesc - channel->lmdesc.base)); +} + static void rz_dmac_lmdesc_recycle(struct rz_dmac_chan *channel) { struct rz_lmdesc *lmdesc = channel->lmdesc.head; @@ -272,30 +303,38 @@ static void rz_dmac_lmdesc_recycle(struct rz_dmac_chan *channel) channel->lmdesc.head = lmdesc; } +static bool rz_dmac_chan_is_enabled(struct rz_dmac_chan *channel) +{ + u32 val = rz_dmac_ch_readl(channel, CHSTAT, 1); + + return !!(val & CHSTAT_EN); +} + +static bool rz_dmac_chan_is_paused(struct rz_dmac_chan *channel) +{ + u32 val = rz_dmac_ch_readl(channel, CHSTAT, 1); + + return !!(val & CHSTAT_SUS); +} + static void rz_dmac_enable_hw(struct rz_dmac_chan *channel) { struct dma_chan *chan = &channel->vc.chan; struct rz_dmac *dmac = to_rz_dmac(chan->device); u32 nxla; u32 chctrl; - u32 chstat; dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index); rz_dmac_lmdesc_recycle(channel); - nxla = channel->lmdesc.base_dma + - (sizeof(struct rz_lmdesc) * (channel->lmdesc.head - - channel->lmdesc.base)); + nxla = rz_dmac_lmdesc_addr(channel, channel->lmdesc.head); - chstat = rz_dmac_ch_readl(channel, CHSTAT, 1); - if (!(chstat & CHSTAT_EN)) { - chctrl = (channel->chctrl | CHCTRL_SETEN); - rz_dmac_ch_writel(channel, nxla, NXLA, 1); - rz_dmac_ch_writel(channel, channel->chcfg, CHCFG, 1); - rz_dmac_ch_writel(channel, CHCTRL_SWRST, CHCTRL, 1); - rz_dmac_ch_writel(channel, chctrl, CHCTRL, 1); - } + chctrl = (channel->chctrl | CHCTRL_SETEN); + rz_dmac_ch_writel(channel, nxla, NXLA, 1); + rz_dmac_ch_writel(channel, channel->chcfg, CHCFG, 1); + rz_dmac_ch_writel(channel, CHCTRL_SWRST, CHCTRL, 1); + rz_dmac_ch_writel(channel, chctrl, CHCTRL, 1); } static void rz_dmac_disable_hw(struct rz_dmac_chan *channel) @@ -331,6 +370,60 @@ static void rz_dmac_set_dma_req_no(struct rz_dmac *dmac, unsigned int index, rz_dmac_set_dmars_register(dmac, index, req_no); } +/* + * Map MID/RID request number (bits[0:9] of DMA specifier) to the ICU + * DMA ACK signal number, per RZ/G3E hardware manual Table 4.6-28. + * + * Three peripheral groups cover all ACK-capable peripherals: + * + * PFC external DMA pins (DREQ0..DREQ4): + * req_no 0x000-0x004 -> ACK No. 84-88 (ack = req_no + 84) + * + * SSIU BUSIFs (ssip00..ssip93): + * req_no 0x161-0x198 -> ACK No. 28-83 (ack = req_no - 0x145) + * + * SPDIF (CH0..CH2) + SCU SRC (sr0..sr9) + DVC (cmd0..cmd1): + * req_no 0x199-0x1b4 -> ACK No. 0-27 (ack = req_no - 0x199) + */ +static int rz_dmac_get_ack_no(const struct rz_dmac_info *info, u16 req_no) +{ + if (!info->icu_register_dma_ack) + return -EINVAL; + + switch (req_no) { + case 0x000 ... 0x004: + /* PFC external DMA pins: ACK No. 84-88 */ + return req_no + 84; + case 0x161 ... 0x198: + /* SSIU BUSIFs: ACK No. 28-83 */ + return req_no - 0x145; + case 0x199 ... 0x1b4: + /* SPDIF + SCU SRC + DVC: ACK No. 0-27 */ + return req_no - 0x199; + default: + return -EINVAL; + } +} + +static void rz_dmac_set_dma_ack_no(struct rz_dmac *dmac, unsigned int index, + int ack_no) +{ + if (ack_no < 0 || !dmac->info->icu_register_dma_ack) + return; + + dmac->info->icu_register_dma_ack(dmac->icu.pdev, dmac->icu.dmac_index, + index, ack_no); +} + +static void rz_dmac_reset_dma_ack_no(struct rz_dmac *dmac, int ack_no) +{ + if (ack_no < 0 || !dmac->info->icu_register_dma_ack) + return; + + dmac->info->icu_register_dma_ack(dmac->icu.pdev, dmac->icu.dmac_index, + dmac->info->default_dma_ack_no, ack_no); +} + static void rz_dmac_prepare_desc_for_memcpy(struct rz_dmac_chan *channel) { struct dma_chan *chan = &channel->vc.chan; @@ -339,6 +432,8 @@ static void rz_dmac_prepare_desc_for_memcpy(struct rz_dmac_chan *channel) struct rz_dmac_desc *d = channel->desc; u32 chcfg = CHCFG_MEM_COPY; + d->start_lmdesc = lmdesc; + /* prepare descriptor */ lmdesc->sa = d->src; lmdesc->da = d->dest; @@ -346,12 +441,12 @@ static void rz_dmac_prepare_desc_for_memcpy(struct rz_dmac_chan *channel) lmdesc->chcfg = chcfg; lmdesc->chitvl = 0; lmdesc->chext = 0; - lmdesc->header = HEADER_LV; + lmdesc->header = HEADER_LV | HEADER_LE; rz_dmac_set_dma_req_no(dmac, channel->index, dmac->info->default_dma_req_no); channel->chcfg = chcfg; - channel->chctrl = CHCTRL_STG | CHCTRL_SETEN; + channel->chctrl = CHCTRL_STG; } static void rz_dmac_prepare_descs_for_slave_sg(struct rz_dmac_chan *channel) @@ -373,6 +468,7 @@ static void rz_dmac_prepare_descs_for_slave_sg(struct rz_dmac_chan *channel) } lmdesc = channel->lmdesc.tail; + d->start_lmdesc = lmdesc; for (i = 0, sg = sgl; i < sg_len; i++, sg = sg_next(sg)) { if (d->direction == DMA_DEV_TO_MEM) { @@ -388,7 +484,7 @@ static void rz_dmac_prepare_descs_for_slave_sg(struct rz_dmac_chan *channel) lmdesc->chext = 0; if (i == (sg_len - 1)) { lmdesc->chcfg = (channel->chcfg & ~CHCFG_DEM); - lmdesc->header = HEADER_LV; + lmdesc->header = HEADER_LV | HEADER_LE; } else { lmdesc->chcfg = channel->chcfg; lmdesc->header = HEADER_LV; @@ -400,22 +496,77 @@ static void rz_dmac_prepare_descs_for_slave_sg(struct rz_dmac_chan *channel) channel->lmdesc.tail = lmdesc; rz_dmac_set_dma_req_no(dmac, channel->index, channel->mid_rid); + rz_dmac_set_dma_ack_no(dmac, channel->index, channel->dmac_ack); - channel->chctrl = CHCTRL_SETEN; + channel->chctrl = 0; } -static int rz_dmac_xfer_desc(struct rz_dmac_chan *chan) +static void rz_dmac_prepare_descs_for_cyclic(struct rz_dmac_chan *channel) +{ + struct dma_chan *chan = &channel->vc.chan; + struct rz_dmac *dmac = to_rz_dmac(chan->device); + struct rz_dmac_desc *d = channel->desc; + size_t period_len = d->sgcount; + struct rz_lmdesc *lmdesc; + size_t buf_len = d->len; + size_t periods = buf_len / period_len; + + lockdep_assert_held(&channel->vc.lock); + + channel->chcfg |= CHCFG_SEL(channel->index) | CHCFG_DMS; + + if (d->direction == DMA_DEV_TO_MEM) { + channel->chcfg |= CHCFG_SAD; + channel->chcfg &= ~CHCFG_REQD; + } else { + channel->chcfg |= CHCFG_DAD | CHCFG_REQD; + } + + lmdesc = channel->lmdesc.tail; + d->start_lmdesc = lmdesc; + + for (size_t i = 0; i < periods; i++) { + if (d->direction == DMA_DEV_TO_MEM) { + lmdesc->sa = d->src; + lmdesc->da = d->dest + (i * period_len); + } else { + lmdesc->sa = d->src + (i * period_len); + lmdesc->da = d->dest; + } + + lmdesc->tb = period_len; + lmdesc->chitvl = 0; + lmdesc->chext = 0; + lmdesc->chcfg = channel->chcfg; + lmdesc->header = HEADER_LV | HEADER_WBD; + + if (i == periods - 1) + lmdesc->nxla = rz_dmac_lmdesc_addr(channel, d->start_lmdesc); + + if (++lmdesc >= (channel->lmdesc.base + DMAC_NR_LMDESC)) + lmdesc = channel->lmdesc.base; + } + + channel->lmdesc.tail = lmdesc; + + rz_dmac_set_dma_req_no(dmac, channel->index, channel->mid_rid); + rz_dmac_set_dma_ack_no(dmac, channel->index, channel->dmac_ack); +} + +static void rz_dmac_xfer_desc(struct rz_dmac_chan *chan) { - struct rz_dmac_desc *d = chan->desc; struct virt_dma_desc *vd; vd = vchan_next_desc(&chan->vc); - if (!vd) - return 0; + if (!vd) { + chan->desc = NULL; + return; + } list_del(&vd->node); + chan->desc = to_rz_dmac_desc(vd); - switch (d->type) { + switch (chan->desc->type) { case RZ_DMAC_DESC_MEMCPY: rz_dmac_prepare_desc_for_memcpy(chan); break; @@ -424,13 +575,12 @@ static int rz_dmac_xfer_desc(struct rz_dmac_chan *chan) rz_dmac_prepare_descs_for_slave_sg(chan); break; - default: - return -EINVAL; + case RZ_DMAC_DESC_CYCLIC: + rz_dmac_prepare_descs_for_cyclic(chan); + break; } rz_dmac_enable_hw(chan); - - return 0; } /* @@ -466,29 +616,47 @@ static void rz_dmac_free_chan_resources(struct dma_chan *chan) struct rz_dmac *dmac = to_rz_dmac(chan->device); struct rz_dmac_desc *desc, *_desc; unsigned long flags; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) { + dev_err(dmac->dev, "RPM resume failed for channel %s, ret=%d\n!", + dma_chan_name(chan), ret); + } spin_lock_irqsave(&channel->vc.lock, flags); rz_lmdesc_setup(channel, channel->lmdesc.base); - rz_dmac_disable_hw(channel); - list_splice_tail_init(&channel->ld_active, &channel->ld_free); - list_splice_tail_init(&channel->ld_queue, &channel->ld_free); + /* Skip touching HW if RPM resume failed. Let the cleanup do its jobs. */ + if (!ret) + rz_dmac_disable_hw(channel); if (channel->mid_rid >= 0) { clear_bit(channel->mid_rid, dmac->modules); channel->mid_rid = -EINVAL; } + channel->status = 0; + rz_dmac_reset_dma_ack_no(dmac, channel->dmac_ack); + channel->dmac_ack = -EINVAL; + spin_unlock_irqrestore(&channel->vc.lock, flags); + vchan_free_chan_resources(&channel->vc); + + spin_lock_irqsave(&channel->vc.lock, flags); + list_for_each_entry_safe(desc, _desc, &channel->ld_free, node) { + list_del(&desc->node); kfree(desc); channel->descs_allocated--; } INIT_LIST_HEAD(&channel->ld_free); - vchan_free_chan_resources(&channel->vc); + + spin_unlock_irqrestore(&channel->vc.lock, flags); } static struct dma_async_tx_descriptor * @@ -503,20 +671,19 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, __func__, channel->index, &src, &dest, len); scoped_guard(spinlock_irqsave, &channel->vc.lock) { - if (list_empty(&channel->ld_free)) + desc = list_first_entry_or_null(&channel->ld_free, struct rz_dmac_desc, node); + if (!desc) return NULL; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); - - desc->type = RZ_DMAC_DESC_MEMCPY; - desc->src = src; - desc->dest = dest; - desc->len = len; - desc->direction = DMA_MEM_TO_MEM; - - list_move_tail(channel->ld_free.next, &channel->ld_queue); + list_del(&desc->node); } + desc->type = RZ_DMAC_DESC_MEMCPY; + desc->src = src; + desc->dest = dest; + desc->len = len; + desc->direction = DMA_MEM_TO_MEM; + return vchan_tx_prep(&channel->vc, &desc->vd, flags); } @@ -533,26 +700,74 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, int i = 0; scoped_guard(spinlock_irqsave, &channel->vc.lock) { - if (list_empty(&channel->ld_free)) + desc = list_first_entry_or_null(&channel->ld_free, struct rz_dmac_desc, node); + if (!desc) + return NULL; + + list_del(&desc->node); + } + + for_each_sg(sgl, sg, sg_len, i) + dma_length += sg_dma_len(sg); + + desc->type = RZ_DMAC_DESC_SLAVE_SG; + desc->sg = sgl; + desc->sgcount = sg_len; + desc->len = dma_length; + desc->direction = direction; + + if (direction == DMA_DEV_TO_MEM) + desc->src = channel->src_per_address; + else + desc->dest = channel->dst_per_address; + + return vchan_tx_prep(&channel->vc, &desc->vd, flags); +} + +static struct dma_async_tx_descriptor * +rz_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, + size_t buf_len, size_t period_len, + enum dma_transfer_direction direction, + unsigned long flags) +{ + struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); + struct rz_dmac_desc *desc; + size_t periods; + + if (!is_slave_direction(direction)) + return NULL; + + if (!period_len || !buf_len) + return NULL; + + periods = buf_len / period_len; + if (!periods || periods > DMAC_NR_LMDESC) + return NULL; + + scoped_guard(spinlock_irqsave, &channel->vc.lock) { + if (channel->status & BIT(RZ_DMAC_CHAN_STATUS_CYCLIC)) return NULL; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + desc = list_first_entry_or_null(&channel->ld_free, struct rz_dmac_desc, node); + if (!desc) + return NULL; - for_each_sg(sgl, sg, sg_len, i) - dma_length += sg_dma_len(sg); + list_del(&desc->node); - desc->type = RZ_DMAC_DESC_SLAVE_SG; - desc->sg = sgl; - desc->sgcount = sg_len; - desc->len = dma_length; - desc->direction = direction; + channel->status |= BIT(RZ_DMAC_CHAN_STATUS_CYCLIC); + } - if (direction == DMA_DEV_TO_MEM) - desc->src = channel->src_per_address; - else - desc->dest = channel->dst_per_address; + desc->type = RZ_DMAC_DESC_CYCLIC; + desc->sgcount = period_len; + desc->len = buf_len; + desc->direction = direction; - list_move_tail(channel->ld_free.next, &channel->ld_queue); + if (direction == DMA_DEV_TO_MEM) { + desc->src = channel->src_per_address; + desc->dest = buf_addr; + } else { + desc->src = buf_addr; + desc->dest = channel->dst_per_address; } return vchan_tx_prep(&channel->vc, &desc->vd, flags); @@ -561,44 +776,59 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, static int rz_dmac_terminate_all(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); + struct rz_dmac *dmac = to_rz_dmac(chan->device); unsigned long flags; LIST_HEAD(head); + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) { + dev_err(dmac->dev, "RPM resume failed for channel %s, ret=%d\n!", + dma_chan_name(chan), ret); + } spin_lock_irqsave(&channel->vc.lock, flags); - rz_dmac_disable_hw(channel); + /* Don't return if RPM failed. Let the cleanup do its jobs. */ + if (!ret) + rz_dmac_disable_hw(channel); rz_lmdesc_setup(channel, channel->lmdesc.base); - list_splice_tail_init(&channel->ld_active, &channel->ld_free); - list_splice_tail_init(&channel->ld_queue, &channel->ld_free); + if (channel->desc) { + vchan_terminate_vdesc(&channel->desc->vd); + channel->desc = NULL; + } + vchan_get_all_descriptors(&channel->vc, &head); + + channel->status = 0; + spin_unlock_irqrestore(&channel->vc.lock, flags); vchan_dma_desc_free_list(&channel->vc, &head); - return 0; + return ret; } static void rz_dmac_issue_pending(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); struct rz_dmac *dmac = to_rz_dmac(chan->device); - struct rz_dmac_desc *desc; unsigned long flags; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return; spin_lock_irqsave(&channel->vc.lock, flags); - if (!list_empty(&channel->ld_queue)) { - desc = list_first_entry(&channel->ld_queue, - struct rz_dmac_desc, node); - channel->desc = desc; - if (vchan_issue_pending(&channel->vc)) { - if (rz_dmac_xfer_desc(channel) < 0) - dev_warn(dmac->dev, "ch: %d couldn't issue DMA xfer\n", - channel->index); - else - list_move_tail(channel->ld_queue.next, - &channel->ld_active); - } - } + /* + * Issue the descriptor. If another transfer is already in progress, the + * issued descriptor will be handled after the current transfer finishes. + */ + if (vchan_issue_pending(&channel->vc) && !channel->desc) + rz_dmac_xfer_desc(channel); spin_unlock_irqrestore(&channel->vc.lock, flags); } @@ -656,13 +886,13 @@ static int rz_dmac_config(struct dma_chan *chan, static void rz_dmac_virt_desc_free(struct virt_dma_desc *vd) { - /* - * Place holder - * Descriptor allocation is done during alloc_chan_resources and - * get freed during free_chan_resources. - * list is used to manage the descriptors and avoid any memory - * allocation/free during DMA read/write. - */ + struct rz_dmac_chan *channel = to_rz_dmac_chan(vd->tx.chan); + struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan); + struct rz_dmac_desc *desc = to_rz_dmac_desc(vd); + + guard(spinlock_irqsave)(&vc->lock); + + list_add_tail(&desc->node, &channel->ld_free); } static void rz_dmac_device_synchronize(struct dma_chan *chan) @@ -672,12 +902,20 @@ static void rz_dmac_device_synchronize(struct dma_chan *chan) u32 chstat; int ret; + vchan_synchronize(&channel->vc); + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return; + ret = read_poll_timeout(rz_dmac_ch_readl, chstat, !(chstat & CHSTAT_EN), 100, 100000, false, channel, CHSTAT, 1); if (ret < 0) dev_warn(dmac->dev, "DMA Timeout"); rz_dmac_set_dma_req_no(dmac, channel->index, dmac->info->default_dma_req_no); + rz_dmac_reset_dma_ack_no(dmac, channel->dmac_ack); } static struct rz_lmdesc * @@ -691,9 +929,10 @@ rz_dmac_get_next_lmdesc(struct rz_lmdesc *base, struct rz_lmdesc *lmdesc) return next; } -static u32 rz_dmac_calculate_residue_bytes_in_vd(struct rz_dmac_chan *channel, u32 crla) +static u32 rz_dmac_calculate_residue_bytes_in_vd(struct rz_dmac_chan *channel, + struct rz_dmac_desc *desc, u32 crla) { - struct rz_lmdesc *lmdesc = channel->lmdesc.head; + struct rz_lmdesc *lmdesc = desc->start_lmdesc; struct dma_chan *chan = &channel->vc.chan; struct rz_dmac *dmac = to_rz_dmac(chan->device); u32 residue = 0, i = 0; @@ -705,9 +944,18 @@ static u32 rz_dmac_calculate_residue_bytes_in_vd(struct rz_dmac_chan *channel, u } /* Calculate residue from next lmdesc to end of virtual desc */ - while (lmdesc->chcfg & CHCFG_DEM) { - residue += lmdesc->tb; - lmdesc = rz_dmac_get_next_lmdesc(channel->lmdesc.base, lmdesc); + if (channel->status & BIT(RZ_DMAC_CHAN_STATUS_CYCLIC)) { + u32 start_lmdesc_addr = rz_dmac_lmdesc_addr(channel, desc->start_lmdesc); + + while (lmdesc->nxla != start_lmdesc_addr) { + residue += lmdesc->tb; + lmdesc = rz_dmac_get_next_lmdesc(channel->lmdesc.base, lmdesc); + } + } else { + while (lmdesc->chcfg & CHCFG_DEM) { + residue += lmdesc->tb; + lmdesc = rz_dmac_get_next_lmdesc(channel->lmdesc.base, lmdesc); + } } dev_dbg(dmac->dev, "%s: VD residue is %u\n", __func__, residue); @@ -715,64 +963,36 @@ static u32 rz_dmac_calculate_residue_bytes_in_vd(struct rz_dmac_chan *channel, u return residue; } -static u32 rz_dmac_chan_get_residue(struct rz_dmac_chan *channel, - dma_cookie_t cookie) +static int rz_dmac_chan_get_residue(struct device *dev, struct rz_dmac_chan *channel, + dma_cookie_t cookie, u32 *residue) { - struct rz_dmac_desc *current_desc, *desc; - enum dma_status status; + struct rz_dmac_desc *desc = NULL; + struct virt_dma_desc *vd; u32 crla, crtb, i; + int ret; - /* Get current processing virtual descriptor */ - current_desc = list_first_entry(&channel->ld_active, - struct rz_dmac_desc, node); - if (!current_desc) - return 0; - - /* - * If the cookie corresponds to a descriptor that has been completed - * there is no residue. The same check has already been performed by the - * caller but without holding the channel lock, so the descriptor could - * now be complete. - */ - status = dma_cookie_status(&channel->vc.chan, cookie, NULL); - if (status == DMA_COMPLETE) + vd = vchan_find_desc(&channel->vc, cookie); + if (vd) { + /* Descriptor has been issued but not yet processed. */ + desc = to_rz_dmac_desc(vd); + *residue = desc->len; return 0; + } else if (channel->desc && channel->desc->vd.tx.cookie == cookie) { + /* Descriptor is currently processed. */ + desc = channel->desc; + } - /* - * If the cookie doesn't correspond to the currently processing virtual - * descriptor then the descriptor hasn't been processed yet, and the - * residue is equal to the full descriptor size. Also, a client driver - * is possible to call this function before rz_dmac_irq_handler_thread() - * runs. In this case, the running descriptor will be the next - * descriptor, and will appear in the done list. So, if the argument - * cookie matches the done list's cookie, we can assume the residue is - * zero. - */ - if (cookie != current_desc->vd.tx.cookie) { - list_for_each_entry(desc, &channel->ld_free, node) { - if (cookie == desc->vd.tx.cookie) - return 0; - } - - list_for_each_entry(desc, &channel->ld_queue, node) { - if (cookie == desc->vd.tx.cookie) - return desc->len; - } - - list_for_each_entry(desc, &channel->ld_active, node) { - if (cookie == desc->vd.tx.cookie) - return desc->len; - } - - /* - * No descriptor found for the cookie, there's thus no residue. - * This shouldn't happen if the calling driver passes a correct - * cookie value. - */ - WARN(1, "No descriptor for cookie!"); + if (!desc) { + /* Descriptor was not found. May be already completed by now. */ + *residue = 0; return 0; } + PM_RUNTIME_ACQUIRE_IF_ENABLED(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + /* * We need to read two registers. Make sure the hardware does not move * to next lmdesc while reading the current lmdesc. Trying it 3 times @@ -792,7 +1012,9 @@ static u32 rz_dmac_chan_get_residue(struct rz_dmac_chan *channel, * Calculate number of bytes transferred in processing virtual descriptor. * One virtual descriptor can have many lmdesc. */ - return crtb + rz_dmac_calculate_residue_bytes_in_vd(channel, crla); + *residue = crtb + rz_dmac_calculate_residue_bytes_in_vd(channel, desc, crla); + + return 0; } static enum dma_status rz_dmac_tx_status(struct dma_chan *chan, @@ -800,62 +1022,155 @@ static enum dma_status rz_dmac_tx_status(struct dma_chan *chan, struct dma_tx_state *txstate) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); + struct rz_dmac *dmac = to_rz_dmac(chan->device); enum dma_status status; u32 residue; - status = dma_cookie_status(chan, cookie, txstate); - if (status == DMA_COMPLETE || !txstate) - return status; - scoped_guard(spinlock_irqsave, &channel->vc.lock) { - u32 val; + int ret; + + status = dma_cookie_status(chan, cookie, txstate); + if (status == DMA_COMPLETE || !txstate) + return status; - residue = rz_dmac_chan_get_residue(channel, cookie); + ret = rz_dmac_chan_get_residue(dmac->dev, channel, cookie, &residue); + if (ret) + return DMA_ERROR; - val = rz_dmac_ch_readl(channel, CHSTAT, 1); - if (val & CHSTAT_SUS) + if (status == DMA_IN_PROGRESS && rz_dmac_chan_is_paused(channel)) status = DMA_PAUSED; } - /* if there's no residue and no paused, the cookie is complete */ - if (!residue && status != DMA_PAUSED) - return DMA_COMPLETE; - dma_set_residue(txstate, residue); return status; } +static int rz_dmac_device_pause_set(struct rz_dmac_chan *channel, + unsigned long set_bitmask) +{ + int ret = 0; + u32 val; + + lockdep_assert_held(&channel->vc.lock); + + if (!rz_dmac_chan_is_enabled(channel)) + return 0; + + if (rz_dmac_chan_is_paused(channel)) + goto set_bit; + + rz_dmac_ch_writel(channel, CHCTRL_SETSUS, CHCTRL, 1); + ret = read_poll_timeout_atomic(rz_dmac_ch_readl, val, + (val & CHSTAT_SUS), 1, 1024, false, + channel, CHSTAT, 1); + +set_bit: + channel->status |= set_bitmask; + + return ret; +} + static int rz_dmac_device_pause(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); - u32 val; + struct rz_dmac *dmac = to_rz_dmac(chan->device); + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; guard(spinlock_irqsave)(&channel->vc.lock); - val = rz_dmac_ch_readl(channel, CHSTAT, 1); - if (!(val & CHSTAT_EN)) + return rz_dmac_device_pause_set(channel, BIT(RZ_DMAC_CHAN_STATUS_PAUSED)); +} + +static int rz_dmac_device_pause_internal(struct rz_dmac_chan *channel) +{ + lockdep_assert_held(&channel->vc.lock); + + /* Skip channels explicitly paused by consummers or disabled. */ + if (channel->status & BIT(RZ_DMAC_CHAN_STATUS_PAUSED) || + !rz_dmac_chan_is_enabled(channel)) return 0; - rz_dmac_ch_writel(channel, CHCTRL_SETSUS, CHCTRL, 1); - return read_poll_timeout_atomic(rz_dmac_ch_readl, val, - (val & CHSTAT_SUS), 1, 1024, - false, channel, CHSTAT, 1); + return rz_dmac_device_pause_set(channel, BIT(RZ_DMAC_CHAN_STATUS_PAUSED_INTERNAL)); +} + +static int rz_dmac_device_resume_set(struct rz_dmac_chan *channel, + unsigned long clear_bitmask) +{ + u32 val; + int ret; + + lockdep_assert_held(&channel->vc.lock); + + /* + * We can be: + * + * 1/ after the channel was paused by a consummer and now it + * needs to be resummed + * 2/ after the channel was paused internally (as a result of + * a system suspend with power loss or not) + * 3/ after the channel was paused by a consummer, the system + * went through a system suspend (with power loss or not) + * and the consummer wants to resume the channel + * + * To cover all the above cases we set both CLRSUS and SETEN. + * + * In case 1/ setting SETEN while the channel is still enabled + * is harmless for the controller. + * + * In case 2/ the channel is disabled when calling this function + * and setting CLRSUS is harmless for the controller as the + * channel is disabled anyway. + * + * In case 3/ the channel is disabled/enabled if the system + * went though a suspend with power loss/or not and setting + * CLRSUS/SETEN is harmless for the controller as the channel + * is enabled/disabled anyway. + */ + + rz_dmac_ch_writel(channel, CHCTRL_CLRSUS | CHCTRL_SETEN, CHCTRL, 1); + + ret = read_poll_timeout_atomic(rz_dmac_ch_readl, val, + ((val & (CHSTAT_SUS | CHSTAT_EN)) == CHSTAT_EN), + 1, 1024, false, channel, CHSTAT, 1); + + channel->status &= ~clear_bitmask; + + return ret; } static int rz_dmac_device_resume(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); - u32 val; + struct rz_dmac *dmac = to_rz_dmac(chan->device); + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; guard(spinlock_irqsave)(&channel->vc.lock); - /* Do not check CHSTAT_SUS but rely on HW capabilities. */ + if (!(channel->status & BIT(RZ_DMAC_CHAN_STATUS_PAUSED))) + return 0; + + return rz_dmac_device_resume_set(channel, BIT(RZ_DMAC_CHAN_STATUS_PAUSED)); +} + +static int rz_dmac_device_resume_internal(struct rz_dmac_chan *channel) +{ + lockdep_assert_held(&channel->vc.lock); + + if (!(channel->status & BIT(RZ_DMAC_CHAN_STATUS_PAUSED_INTERNAL))) + return 0; - rz_dmac_ch_writel(channel, CHCTRL_CLRSUS, CHCTRL, 1); - return read_poll_timeout_atomic(rz_dmac_ch_readl, val, - !(val & CHSTAT_SUS), 1, 1024, - false, channel, CHSTAT, 1); + return rz_dmac_device_resume_set(channel, BIT(RZ_DMAC_CHAN_STATUS_PAUSED_INTERNAL)); } /* @@ -875,7 +1190,7 @@ static void rz_dmac_irq_handle_channel(struct rz_dmac_chan *channel) channel->index, chstat); scoped_guard(spinlock_irqsave, &channel->vc.lock) - rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1); + rz_dmac_disable_hw(channel); return; } @@ -901,28 +1216,22 @@ static irqreturn_t rz_dmac_irq_handler(int irq, void *dev_id) static irqreturn_t rz_dmac_irq_handler_thread(int irq, void *dev_id) { struct rz_dmac_chan *channel = dev_id; - struct rz_dmac_desc *desc = NULL; - unsigned long flags; + struct rz_dmac_desc *desc; - spin_lock_irqsave(&channel->vc.lock, flags); + guard(spinlock_irqsave)(&channel->vc.lock); - if (list_empty(&channel->ld_active)) { - /* Someone might have called terminate all */ - goto out; - } + desc = channel->desc; + if (!desc) + return IRQ_HANDLED; - desc = list_first_entry(&channel->ld_active, struct rz_dmac_desc, node); - vchan_cookie_complete(&desc->vd); - list_move_tail(channel->ld_active.next, &channel->ld_free); - if (!list_empty(&channel->ld_queue)) { - desc = list_first_entry(&channel->ld_queue, struct rz_dmac_desc, - node); - channel->desc = desc; - if (rz_dmac_xfer_desc(channel) == 0) - list_move_tail(channel->ld_queue.next, &channel->ld_active); + if (channel->status & BIT(RZ_DMAC_CHAN_STATUS_CYCLIC)) { + vchan_cyclic_callback(&desc->vd); + } else { + vchan_cookie_complete(&desc->vd); + channel->desc = NULL; + + rz_dmac_xfer_desc(channel); } -out: - spin_unlock_irqrestore(&channel->vc.lock, flags); return IRQ_HANDLED; } @@ -944,6 +1253,8 @@ static bool rz_dmac_chan_filter(struct dma_chan *chan, void *arg) channel->chcfg = CHCFG_FILL_TM(ch_cfg) | CHCFG_FILL_AM(ch_cfg) | CHCFG_FILL_LVL(ch_cfg) | CHCFG_FILL_HIEN(ch_cfg); + channel->dmac_ack = rz_dmac_get_ack_no(dmac->info, channel->mid_rid); + return !test_and_set_bit(channel->mid_rid, dmac->modules); } @@ -980,25 +1291,7 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, channel->index = index; channel->mid_rid = -EINVAL; - - /* Request the channel interrupt. */ - scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index); - irq = platform_get_irq_byname(pdev, pdev_irqname); - if (irq < 0) - return irq; - - irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", - dev_name(dmac->dev), index); - if (!irqname) - return -ENOMEM; - - ret = devm_request_threaded_irq(dmac->dev, irq, rz_dmac_irq_handler, - rz_dmac_irq_handler_thread, 0, - irqname, channel); - if (ret) { - dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", irq, ret); - return ret; - } + channel->dmac_ack = -EINVAL; /* Set io base address for each channel */ if (index < 8) { @@ -1012,25 +1305,40 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, } /* Allocate descriptors */ - lmdesc = dma_alloc_coherent(&pdev->dev, - sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, - &channel->lmdesc.base_dma, GFP_KERNEL); + lmdesc = dmam_alloc_coherent(&pdev->dev, + sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, + &channel->lmdesc.base_dma, GFP_KERNEL); if (!lmdesc) { dev_err(&pdev->dev, "Can't allocate memory (lmdesc)\n"); return -ENOMEM; } rz_lmdesc_setup(channel, lmdesc); - /* Initialize register for each channel */ - rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1); - channel->vc.desc_free = rz_dmac_virt_desc_free; vchan_init(&channel->vc, &dmac->engine); - INIT_LIST_HEAD(&channel->ld_queue); INIT_LIST_HEAD(&channel->ld_free); - INIT_LIST_HEAD(&channel->ld_active); - return 0; + /* Initialize register for each channel */ + rz_dmac_disable_hw(channel); + + /* Request the channel interrupt. */ + scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index); + irq = platform_get_irq_byname(pdev, pdev_irqname); + if (irq < 0) + return irq; + + irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", + dev_name(dmac->dev), index); + if (!irqname) + return -ENOMEM; + + ret = devm_request_threaded_irq(dmac->dev, irq, rz_dmac_irq_handler, + rz_dmac_irq_handler_thread, 0, + irqname, channel); + if (ret) + dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", irq, ret); + + return ret; } static void rz_dmac_put_device(void *_dev) @@ -1099,7 +1407,6 @@ static int rz_dmac_probe(struct platform_device *pdev) const char *irqname = "error"; struct dma_device *engine; struct rz_dmac *dmac; - int channel_num; int ret; int irq; u8 i; @@ -1132,18 +1439,6 @@ static int rz_dmac_probe(struct platform_device *pdev) return PTR_ERR(dmac->ext_base); } - /* Register interrupt handler for error */ - irq = platform_get_irq_byname_optional(pdev, irqname); - if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0, - irqname, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n", - irq, ret); - return ret; - } - } - /* Initialize the channels. */ INIT_LIST_HEAD(&dmac->engine.channels); @@ -1152,6 +1447,7 @@ static int rz_dmac_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(dmac->rstc), "failed to get resets\n"); + pm_runtime_irq_safe(&pdev->dev); pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) { @@ -1169,6 +1465,18 @@ static int rz_dmac_probe(struct platform_device *pdev) goto err; } + /* Register interrupt handler for error */ + irq = platform_get_irq_byname_optional(pdev, irqname); + if (irq > 0) { + ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0, + irqname, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n", + irq, ret); + goto err; + } + } + /* Register the DMAC as a DMA provider for DT. */ ret = of_dma_controller_register(pdev->dev.of_node, rz_dmac_of_xlate, NULL); @@ -1179,6 +1487,8 @@ static int rz_dmac_probe(struct platform_device *pdev) engine = &dmac->engine; dma_cap_set(DMA_SLAVE, engine->cap_mask); dma_cap_set(DMA_MEMCPY, engine->cap_mask); + dma_cap_set(DMA_CYCLIC, engine->cap_mask); + engine->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); engine->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_0_7_COMMON_BASE + DCTRL); rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_8_15_COMMON_BASE + DCTRL); @@ -1190,6 +1500,7 @@ static int rz_dmac_probe(struct platform_device *pdev) engine->device_tx_status = rz_dmac_tx_status; engine->device_prep_slave_sg = rz_dmac_prep_slave_sg; engine->device_prep_dma_memcpy = rz_dmac_prep_dma_memcpy; + engine->device_prep_dma_cyclic = rz_dmac_prep_dma_cyclic; engine->device_config = rz_dmac_config; engine->device_terminate_all = rz_dmac_terminate_all; engine->device_issue_pending = rz_dmac_issue_pending; @@ -1210,16 +1521,6 @@ static int rz_dmac_probe(struct platform_device *pdev) dma_register_err: of_dma_controller_free(pdev->dev.of_node); err: - channel_num = i ? i - 1 : 0; - for (i = 0; i < channel_num; i++) { - struct rz_dmac_chan *channel = &dmac->channels[i]; - - dma_free_coherent(&pdev->dev, - sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, - channel->lmdesc.base, - channel->lmdesc.base_dma); - } - reset_control_assert(dmac->rstc); err_pm_runtime_put: pm_runtime_put(&pdev->dev); @@ -1232,25 +1533,135 @@ err_pm_disable: static void rz_dmac_remove(struct platform_device *pdev) { struct rz_dmac *dmac = platform_get_drvdata(pdev); - unsigned int i; dma_async_device_unregister(&dmac->engine); of_dma_controller_free(pdev->dev.of_node); - for (i = 0; i < dmac->n_channels; i++) { - struct rz_dmac_chan *channel = &dmac->channels[i]; - - dma_free_coherent(&pdev->dev, - sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, - channel->lmdesc.base, - channel->lmdesc.base_dma); - } reset_control_assert(dmac->rstc); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); } +static void rz_dmac_suspend_recover(struct rz_dmac *dmac) +{ + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED(dmac->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return; + + for (unsigned int i = 0; i < dmac->n_channels; i++) { + struct rz_dmac_chan *channel = &dmac->channels[i]; + + guard(spinlock_irqsave)(&channel->vc.lock); + + if (!(channel->status & BIT(RZ_DMAC_CHAN_STATUS_CYCLIC))) + continue; + + rz_dmac_device_resume_internal(channel); + } +} + +static int rz_dmac_suspend(struct device *dev) +{ + struct rz_dmac *dmac = dev_get_drvdata(dev); + int ret = 0; + + for (unsigned int i = 0; i < dmac->n_channels; i++) { + struct rz_dmac_chan *channel = &dmac->channels[i]; + + guard(spinlock_irqsave)(&channel->vc.lock); + + if (!(channel->status & BIT(RZ_DMAC_CHAN_STATUS_CYCLIC))) + continue; + + ret = rz_dmac_device_pause_internal(channel); + if (ret) { + dev_err(dev, "Failed to suspend channel %s\n", + dma_chan_name(&channel->vc.chan)); + break; + } + + channel->pm_state.nxla = rz_dmac_ch_readl(channel, NXLA, 1); + } + + if (ret) + goto suspend_recover; + + ret = reset_control_assert(dmac->rstc); + if (ret) + goto suspend_recover; + + ret = pm_runtime_put_sync(dev); + if (ret < 0) + goto reset_deassert; + + return 0; + +reset_deassert: + reset_control_deassert(dmac->rstc); +suspend_recover: + rz_dmac_suspend_recover(dmac); + return ret; +} + +static int rz_dmac_resume(struct device *dev) +{ + struct rz_dmac *dmac = dev_get_drvdata(dev); + int errors = 0, ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = reset_control_deassert(dmac->rstc); + if (ret) { + /* + * Do not put runtime PM here and keep the same state as in + * probe. As subsequent suspend/resume cycles may follow, leave + * the runtime PM as is, here, to avoid imbalances. + */ + return ret; + } + + rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_0_7_COMMON_BASE + DCTRL); + rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_8_15_COMMON_BASE + DCTRL); + + for (unsigned int i = 0; i < dmac->n_channels; i++) { + struct rz_dmac_chan *channel = &dmac->channels[i]; + + guard(spinlock_irqsave)(&channel->vc.lock); + + rz_dmac_disable_hw(&dmac->channels[i]); + + if (!(channel->status & BIT(RZ_DMAC_CHAN_STATUS_CYCLIC))) + continue; + + rz_dmac_set_dma_req_no(dmac, channel->index, channel->mid_rid); + rz_dmac_set_dma_ack_no(dmac, channel->index, channel->dmac_ack); + + rz_dmac_ch_writel(channel, channel->pm_state.nxla, NXLA, 1); + rz_dmac_ch_writel(channel, channel->chcfg, CHCFG, 1); + rz_dmac_ch_writel(channel, CHCTRL_SWRST, CHCTRL, 1); + rz_dmac_ch_writel(channel, channel->chctrl, CHCTRL, 1); + + ret = rz_dmac_device_resume_internal(channel); + if (ret) { + errors = ret; + dev_err(dev, "Failed to resume channel %s, ret=%d\n", + dma_chan_name(&channel->vc.chan), ret); + } + } + + return errors ? : 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(rz_dmac_pm_ops, rz_dmac_suspend, rz_dmac_resume); + static const struct rz_dmac_info rz_dmac_v2h_info = { .icu_register_dma_req = rzv2h_icu_register_dma_req, + .icu_register_dma_ack = rzv2h_icu_register_dma_ack, + .default_dma_ack_no = RZV2H_ICU_DMAC_ACK_NO_DEFAULT, .default_dma_req_no = RZV2H_ICU_DMAC_REQ_NO_DEFAULT, }; @@ -1275,6 +1686,7 @@ static struct platform_driver rz_dmac_driver = { .driver = { .name = "rz-dmac", .of_match_table = of_rz_dmac_match, + .pm = pm_ptr(&rz_dmac_pm_ops), }, .probe = rz_dmac_probe, .remove = rz_dmac_remove, diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 9b803c0aec25..0d9ffa3e2663 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -602,7 +602,6 @@ struct d40_base { struct dma_device dma_both; struct dma_device dma_slave; struct dma_device dma_memcpy; - struct d40_chan *phy_chans; struct d40_chan *log_chans; struct d40_chan **lookup_log_chans; struct d40_chan **lookup_phy_chans; @@ -621,6 +620,7 @@ struct d40_base { u32 *regs_interrupt; u16 gcc_pwr_off_mask; struct d40_gen_dmac gen_dmac; + struct d40_chan phy_chans[]; }; static struct device *chan2dev(struct d40_chan *d40c) @@ -3128,6 +3128,7 @@ static int __init d40_hw_detect_init(struct platform_device *pdev, struct clk *clk; void __iomem *virtbase; struct d40_base *base; + size_t alloc_size; int num_log_chans; int num_phy_chans; int num_memcpy_chans; @@ -3185,22 +3186,24 @@ static int __init d40_hw_detect_init(struct platform_device *pdev, else num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4; + num_phy_chans = min(num_phy_chans, STEDMA40_MAX_PHYS); + /* The number of channels used for memcpy */ if (plat_data->num_of_memcpy_chans) num_memcpy_chans = plat_data->num_of_memcpy_chans; else num_memcpy_chans = ARRAY_SIZE(dma40_memcpy_channels); + num_memcpy_chans = min(num_memcpy_chans, D40_MEMCPY_MAX_CHANS); num_log_chans = num_phy_chans * D40_MAX_LOG_CHAN_PER_PHY; dev_info(dev, "hardware rev: %d with %d physical and %d logical channels\n", rev, num_phy_chans, num_log_chans); - base = devm_kzalloc(dev, - ALIGN(sizeof(struct d40_base), 4) + - (num_phy_chans + num_log_chans + num_memcpy_chans) * - sizeof(struct d40_chan), GFP_KERNEL); + alloc_size = struct_size(base, phy_chans, num_phy_chans); + alloc_size += sizeof(*base->log_chans) * (num_log_chans + num_memcpy_chans); + base = devm_kzalloc(dev, alloc_size, GFP_KERNEL); if (!base) return -ENOMEM; @@ -3213,7 +3216,6 @@ static int __init d40_hw_detect_init(struct platform_device *pdev, base->virtbase = virtbase; base->plat_data = plat_data; base->dev = dev; - base->phy_chans = ((void *)base) + ALIGN(sizeof(struct d40_base), 4); base->log_chans = &base->phy_chans[num_phy_chans]; if (base->plat_data->num_of_phy_chans == 14) { diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c index 5948fbf32c21..64cedef1050a 100644 --- a/drivers/dma/tegra186-gpc-dma.c +++ b/drivers/dma/tegra186-gpc-dma.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_dma.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/slab.h> @@ -22,7 +23,6 @@ #include "virt-dma.h" /* CSR register */ -#define TEGRA_GPCDMA_CHAN_CSR 0x00 #define TEGRA_GPCDMA_CSR_ENB BIT(31) #define TEGRA_GPCDMA_CSR_IE_EOC BIT(30) #define TEGRA_GPCDMA_CSR_ONCE BIT(27) @@ -58,7 +58,6 @@ #define TEGRA_GPCDMA_CSR_WEIGHT GENMASK(13, 10) /* STATUS register */ -#define TEGRA_GPCDMA_CHAN_STATUS 0x004 #define TEGRA_GPCDMA_STATUS_BUSY BIT(31) #define TEGRA_GPCDMA_STATUS_ISE_EOC BIT(30) #define TEGRA_GPCDMA_STATUS_PING_PONG BIT(28) @@ -70,22 +69,13 @@ #define TEGRA_GPCDMA_STATUS_IRQ_STA BIT(21) #define TEGRA_GPCDMA_STATUS_IRQ_TRIG_STA BIT(20) -#define TEGRA_GPCDMA_CHAN_CSRE 0x008 #define TEGRA_GPCDMA_CHAN_CSRE_PAUSE BIT(31) -/* Source address */ -#define TEGRA_GPCDMA_CHAN_SRC_PTR 0x00C - -/* Destination address */ -#define TEGRA_GPCDMA_CHAN_DST_PTR 0x010 - /* High address pointer */ -#define TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR 0x014 #define TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR GENMASK(7, 0) #define TEGRA_GPCDMA_HIGH_ADDR_DST_PTR GENMASK(23, 16) /* MC sequence register */ -#define TEGRA_GPCDMA_CHAN_MCSEQ 0x18 #define TEGRA_GPCDMA_MCSEQ_DATA_SWAP BIT(31) #define TEGRA_GPCDMA_MCSEQ_REQ_COUNT GENMASK(30, 25) #define TEGRA_GPCDMA_MCSEQ_BURST GENMASK(24, 23) @@ -101,7 +91,6 @@ #define TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK GENMASK(6, 0) /* MMIO sequence register */ -#define TEGRA_GPCDMA_CHAN_MMIOSEQ 0x01c #define TEGRA_GPCDMA_MMIOSEQ_DBL_BUF BIT(31) #define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH GENMASK(30, 28) #define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8 \ @@ -120,17 +109,7 @@ #define TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD GENMASK(18, 16) #define TEGRA_GPCDMA_MMIOSEQ_MMIO_PROT GENMASK(8, 7) -/* Channel WCOUNT */ -#define TEGRA_GPCDMA_CHAN_WCOUNT 0x20 - -/* Transfer count */ -#define TEGRA_GPCDMA_CHAN_XFER_COUNT 0x24 - -/* DMA byte count status */ -#define TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS 0x28 - /* Error Status Register */ -#define TEGRA_GPCDMA_CHAN_ERR_STATUS 0x30 #define TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT 8 #define TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK 0xF #define TEGRA_GPCDMA_CHAN_ERR_TYPE(err) ( \ @@ -143,16 +122,6 @@ #define TEGRA_DMA_MC_SLAVE_ERR 0xB #define TEGRA_DMA_MMIO_SLAVE_ERR 0xA -/* Fixed Pattern */ -#define TEGRA_GPCDMA_CHAN_FIXED_PATTERN 0x34 - -#define TEGRA_GPCDMA_CHAN_TZ 0x38 -#define TEGRA_GPCDMA_CHAN_TZ_MMIO_PROT_1 BIT(0) -#define TEGRA_GPCDMA_CHAN_TZ_MC_PROT_1 BIT(1) - -#define TEGRA_GPCDMA_CHAN_SPARE 0x3c -#define TEGRA_GPCDMA_CHAN_SPARE_EN_LEGACY_FC BIT(16) - /* * If any burst is in flight and DMA paused then this is the time to complete * on-flight burst and update DMA status register. @@ -178,21 +147,30 @@ struct tegra_dma_channel; */ struct tegra_dma_chip_data { bool hw_support_pause; + unsigned int addr_bits; unsigned int nr_channels; unsigned int channel_reg_size; unsigned int max_dma_count; + const struct tegra_dma_channel_regs *channel_regs; int (*terminate)(struct tegra_dma_channel *tdc); }; /* DMA channel registers */ struct tegra_dma_channel_regs { u32 csr; - u32 src_ptr; - u32 dst_ptr; - u32 high_addr_ptr; + u32 status; + u32 csre; + u32 src; + u32 dst; + u32 high_addr; + u32 src_high; + u32 dst_high; u32 mc_seq; u32 mmio_seq; u32 wcount; + u32 wxfer; + u32 wstatus; + u32 err_status; u32 fixed_pattern; }; @@ -205,7 +183,13 @@ struct tegra_dma_channel_regs { */ struct tegra_dma_sg_req { unsigned int len; - struct tegra_dma_channel_regs ch_regs; + dma_addr_t src; + dma_addr_t dst; + u32 csr; + u32 mc_seq; + u32 mmio_seq; + u32 wcount; + u32 fixed_pattern; }; /* @@ -228,19 +212,20 @@ struct tegra_dma_desc { * tegra_dma_channel: Channel specific information */ struct tegra_dma_channel { - bool config_init; - char name[30]; - enum dma_transfer_direction sid_dir; - enum dma_status status; - int id; - int irq; - int slave_id; + const struct tegra_dma_channel_regs *regs; struct tegra_dma *tdma; struct virt_dma_chan vc; struct tegra_dma_desc *dma_desc; struct dma_slave_config dma_sconfig; + enum dma_transfer_direction sid_dir; + enum dma_status status; unsigned int stream_id; unsigned long chan_base_offset; + bool config_init; + char name[30]; + int id; + int irq; + int slave_id; }; /* @@ -284,26 +269,55 @@ static inline struct device *tdc2dev(struct tegra_dma_channel *tdc) return tdc->vc.chan.device->dev; } +static void tegra_dma_program_addr(struct tegra_dma_channel *tdc, + struct tegra_dma_sg_req *sg_req) +{ + tdc_write(tdc, tdc->regs->src, lower_32_bits(sg_req->src)); + tdc_write(tdc, tdc->regs->dst, lower_32_bits(sg_req->dst)); + + if (tdc->tdma->chip_data->addr_bits > 39) { + tdc_write(tdc, tdc->regs->src_high, upper_32_bits(sg_req->src)); + tdc_write(tdc, tdc->regs->dst_high, upper_32_bits(sg_req->dst)); + } else { + u32 src_high = FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, + upper_32_bits(sg_req->src)); + u32 dst_high = FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, + upper_32_bits(sg_req->dst)); + + tdc_write(tdc, tdc->regs->high_addr, src_high | dst_high); + } +} + static void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc) { dev_dbg(tdc2dev(tdc), "DMA Channel %d name %s register dump:\n", tdc->id, tdc->name); - dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x SRC %x DST %x\n", - tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_DST_PTR) - ); - dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x BSTA %x\n", - tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_WCOUNT), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT), - tdc_read(tdc, TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS) - ); + dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x\n", + tdc_read(tdc, tdc->regs->csr), + tdc_read(tdc, tdc->regs->status), + tdc_read(tdc, tdc->regs->csre)); + + if (tdc->tdma->chip_data->addr_bits > 39) { + dev_dbg(tdc2dev(tdc), "SRC %x SRC HI %x DST %x DST HI %x\n", + tdc_read(tdc, tdc->regs->src), + tdc_read(tdc, tdc->regs->src_high), + tdc_read(tdc, tdc->regs->dst), + tdc_read(tdc, tdc->regs->dst_high)); + } else { + dev_dbg(tdc2dev(tdc), "SRC %x DST %x HI ADDR %x\n", + tdc_read(tdc, tdc->regs->src), + tdc_read(tdc, tdc->regs->dst), + tdc_read(tdc, tdc->regs->high_addr)); + } + + dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x WSTA %x\n", + tdc_read(tdc, tdc->regs->mc_seq), + tdc_read(tdc, tdc->regs->mmio_seq), + tdc_read(tdc, tdc->regs->wcount), + tdc_read(tdc, tdc->regs->wxfer), + tdc_read(tdc, tdc->regs->wstatus)); dev_dbg(tdc2dev(tdc), "DMA ERR_STA %x\n", - tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS)); + tdc_read(tdc, tdc->regs->err_status)); } static int tegra_dma_sid_reserve(struct tegra_dma_channel *tdc, @@ -377,13 +391,13 @@ static int tegra_dma_pause(struct tegra_dma_channel *tdc) int ret; u32 val; - val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE); + val = tdc_read(tdc, tdc->regs->csre); val |= TEGRA_GPCDMA_CHAN_CSRE_PAUSE; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val); + tdc_write(tdc, tdc->regs->csre, val); /* Wait until busy bit is de-asserted */ ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr + - tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS, + tdc->chan_base_offset + tdc->regs->status, val, !(val & TEGRA_GPCDMA_STATUS_BUSY), TEGRA_GPCDMA_BURST_COMPLETE_TIME, @@ -419,9 +433,9 @@ static void tegra_dma_resume(struct tegra_dma_channel *tdc) { u32 val; - val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE); + val = tdc_read(tdc, tdc->regs->csre); val &= ~TEGRA_GPCDMA_CHAN_CSRE_PAUSE; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val); + tdc_write(tdc, tdc->regs->csre, val); tdc->status = DMA_IN_PROGRESS; } @@ -456,27 +470,27 @@ static void tegra_dma_disable(struct tegra_dma_channel *tdc) { u32 csr, status; - csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR); + csr = tdc_read(tdc, tdc->regs->csr); /* Disable interrupts */ csr &= ~TEGRA_GPCDMA_CSR_IE_EOC; /* Disable DMA */ csr &= ~TEGRA_GPCDMA_CSR_ENB; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr); + tdc_write(tdc, tdc->regs->csr, csr); /* Clear interrupt status if it is there */ - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS); + status = tdc_read(tdc, tdc->regs->status); if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) { dev_dbg(tdc2dev(tdc), "%s():clearing interrupt\n", __func__); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, status); + tdc_write(tdc, tdc->regs->status, status); } } static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc) { struct tegra_dma_desc *dma_desc = tdc->dma_desc; - struct tegra_dma_channel_regs *ch_regs; + struct tegra_dma_sg_req *sg_req; int ret; u32 val; @@ -488,29 +502,27 @@ static void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc) /* Configure next transfer immediately after DMA is busy */ ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr + - tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS, + tdc->chan_base_offset + tdc->regs->status, val, (val & TEGRA_GPCDMA_STATUS_BUSY), 0, TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT); if (ret) return; - ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs; + sg_req = &dma_desc->sg_req[dma_desc->sg_idx]; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr); + tdc_write(tdc, tdc->regs->wcount, sg_req->wcount); + tegra_dma_program_addr(tdc, sg_req); /* Start DMA */ - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, - ch_regs->csr | TEGRA_GPCDMA_CSR_ENB); + tdc_write(tdc, tdc->regs->csr, + sg_req->csr | TEGRA_GPCDMA_CSR_ENB); } static void tegra_dma_start(struct tegra_dma_channel *tdc) { struct tegra_dma_desc *dma_desc = tdc->dma_desc; - struct tegra_dma_channel_regs *ch_regs; + struct tegra_dma_sg_req *sg_req; struct virt_dma_desc *vdesc; if (!dma_desc) { @@ -526,21 +538,19 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc) tegra_dma_resume(tdc); } - ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs; + sg_req = &dma_desc->sg_req[dma_desc->sg_idx]; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 0); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_FIXED_PATTERN, ch_regs->fixed_pattern); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ, ch_regs->mmio_seq); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, ch_regs->mc_seq); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, ch_regs->csr); + tegra_dma_program_addr(tdc, sg_req); + tdc_write(tdc, tdc->regs->wcount, sg_req->wcount); + tdc_write(tdc, tdc->regs->csr, 0); + tdc_write(tdc, tdc->regs->fixed_pattern, sg_req->fixed_pattern); + tdc_write(tdc, tdc->regs->mmio_seq, sg_req->mmio_seq); + tdc_write(tdc, tdc->regs->mc_seq, sg_req->mc_seq); + tdc_write(tdc, tdc->regs->csr, sg_req->csr); /* Start DMA */ - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, - ch_regs->csr | TEGRA_GPCDMA_CSR_ENB); + tdc_write(tdc, tdc->regs->csr, + sg_req->csr | TEGRA_GPCDMA_CSR_ENB); } static void tegra_dma_xfer_complete(struct tegra_dma_channel *tdc) @@ -601,19 +611,19 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id) u32 status; /* Check channel error status register */ - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS); + status = tdc_read(tdc, tdc->regs->err_status); if (status) { tegra_dma_chan_decode_error(tdc, status); tegra_dma_dump_chan_regs(tdc); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS, 0xFFFFFFFF); + tdc_write(tdc, tdc->regs->err_status, 0xFFFFFFFF); } spin_lock(&tdc->vc.lock); - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS); + status = tdc_read(tdc, tdc->regs->status); if (!(status & TEGRA_GPCDMA_STATUS_ISE_EOC)) goto irq_done; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, + tdc_write(tdc, tdc->regs->status, TEGRA_GPCDMA_STATUS_ISE_EOC); if (!dma_desc) @@ -673,10 +683,10 @@ static int tegra_dma_stop_client(struct tegra_dma_channel *tdc) * to stop DMA engine from starting any more bursts for * the given client and wait for in flight bursts to complete */ - csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR); + csr = tdc_read(tdc, tdc->regs->csr); csr &= ~(TEGRA_GPCDMA_CSR_REQ_SEL_MASK); csr |= TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED; - tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr); + tdc_write(tdc, tdc->regs->csr, csr); /* Wait for in flight data transfer to finish */ udelay(TEGRA_GPCDMA_BURST_COMPLETE_TIME); @@ -687,7 +697,7 @@ static int tegra_dma_stop_client(struct tegra_dma_channel *tdc) ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr + tdc->chan_base_offset + - TEGRA_GPCDMA_CHAN_STATUS, + tdc->regs->status, status, !(status & (TEGRA_GPCDMA_STATUS_CHANNEL_TX | TEGRA_GPCDMA_STATUS_CHANNEL_RX)), @@ -739,14 +749,14 @@ static int tegra_dma_get_residual(struct tegra_dma_channel *tdc) unsigned int bytes_xfer, residual; u32 wcount = 0, status; - wcount = tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT); + wcount = tdc_read(tdc, tdc->regs->wxfer); /* * Set wcount = 0 if EOC bit is set. The transfer would have * already completed and the CHAN_XFER_COUNT could have updated * for the next transfer, specifically in case of cyclic transfers. */ - status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS); + status = tdc_read(tdc, tdc->regs->status); if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) wcount = 0; @@ -825,6 +835,13 @@ static unsigned int get_burst_size(struct tegra_dma_channel *tdc, * len to calculate the optimum burst size */ burst_byte = burst_size ? burst_size * slave_bw : len; + + /* + * Find the largest burst size that evenly divides the transfer length. + * The hardware requires the transfer length to be a multiple of the + * burst size - partial bursts are not supported. + */ + burst_byte = min(burst_byte, 1U << __ffs(len)); burst_mmio_width = burst_byte / 4; if (burst_mmio_width < TEGRA_GPCDMA_MMIOSEQ_BURST_MIN) @@ -837,7 +854,7 @@ static unsigned int get_burst_size(struct tegra_dma_channel *tdc, static int get_transfer_param(struct tegra_dma_channel *tdc, enum dma_transfer_direction direction, - u32 *apb_addr, + dma_addr_t *apb_addr, u32 *mmio_seq, u32 *csr, unsigned int *burst_size, @@ -893,7 +910,7 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value, /* Configure default priority weight for the channel */ csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1); - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); + mc_seq = tdc_read(tdc, tdc->regs->mc_seq); /* retain stream-id and clean rest */ mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK; @@ -915,17 +932,15 @@ tegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value, dma_desc->bytes_req = len; dma_desc->sg_count = 1; sg_req = dma_desc->sg_req; + sg_req[0].src = 0; + sg_req[0].dst = dest; - sg_req[0].ch_regs.src_ptr = 0; - sg_req[0].ch_regs.dst_ptr = dest; - sg_req[0].ch_regs.high_addr_ptr = - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32)); - sg_req[0].ch_regs.fixed_pattern = value; + sg_req[0].fixed_pattern = value; /* Word count reg takes value as (N +1) words */ - sg_req[0].ch_regs.wcount = ((len - 4) >> 2); - sg_req[0].ch_regs.csr = csr; - sg_req[0].ch_regs.mmio_seq = 0; - sg_req[0].ch_regs.mc_seq = mc_seq; + sg_req[0].wcount = ((len - 4) >> 2); + sg_req[0].csr = csr; + sg_req[0].mmio_seq = 0; + sg_req[0].mc_seq = mc_seq; sg_req[0].len = len; dma_desc->cyclic = false; @@ -961,7 +976,7 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest, /* Configure default priority weight for the channel */ csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1); - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); + mc_seq = tdc_read(tdc, tdc->regs->mc_seq); /* retain stream-id and clean rest */ mc_seq &= (TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK) | (TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK); @@ -985,17 +1000,14 @@ tegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest, dma_desc->sg_count = 1; sg_req = dma_desc->sg_req; - sg_req[0].ch_regs.src_ptr = src; - sg_req[0].ch_regs.dst_ptr = dest; - sg_req[0].ch_regs.high_addr_ptr = - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (src >> 32)); - sg_req[0].ch_regs.high_addr_ptr |= - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32)); + sg_req[0].src = src; + sg_req[0].dst = dest; + /* Word count reg takes value as (N +1) words */ - sg_req[0].ch_regs.wcount = ((len - 4) >> 2); - sg_req[0].ch_regs.csr = csr; - sg_req[0].ch_regs.mmio_seq = 0; - sg_req[0].ch_regs.mc_seq = mc_seq; + sg_req[0].wcount = ((len - 4) >> 2); + sg_req[0].csr = csr; + sg_req[0].mmio_seq = 0; + sg_req[0].mc_seq = mc_seq; sg_req[0].len = len; dma_desc->cyclic = false; @@ -1010,7 +1022,8 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl, struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); unsigned int max_dma_count = tdc->tdma->chip_data->max_dma_count; enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED; - u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0; + u32 csr, mc_seq, mmio_seq = 0; + dma_addr_t apb_ptr = 0; struct tegra_dma_sg_req *sg_req; struct tegra_dma_desc *dma_desc; struct scatterlist *sg; @@ -1049,7 +1062,7 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl, if (flags & DMA_PREP_INTERRUPT) csr |= TEGRA_GPCDMA_CSR_IE_EOC; - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); + mc_seq = tdc_read(tdc, tdc->regs->mc_seq); /* retain stream-id and clean rest */ mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK; @@ -1096,25 +1109,21 @@ tegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl, dma_desc->bytes_req += len; if (direction == DMA_MEM_TO_DEV) { - sg_req[i].ch_regs.src_ptr = mem; - sg_req[i].ch_regs.dst_ptr = apb_ptr; - sg_req[i].ch_regs.high_addr_ptr = - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32)); + sg_req[i].src = mem; + sg_req[i].dst = apb_ptr; } else if (direction == DMA_DEV_TO_MEM) { - sg_req[i].ch_regs.src_ptr = apb_ptr; - sg_req[i].ch_regs.dst_ptr = mem; - sg_req[i].ch_regs.high_addr_ptr = - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32)); + sg_req[i].src = apb_ptr; + sg_req[i].dst = mem; } /* * Word count register takes input in words. Writing a value * of N into word count register means a req of (N+1) words. */ - sg_req[i].ch_regs.wcount = ((len - 4) >> 2); - sg_req[i].ch_regs.csr = csr; - sg_req[i].ch_regs.mmio_seq = mmio_seq; - sg_req[i].ch_regs.mc_seq = mc_seq; + sg_req[i].wcount = ((len - 4) >> 2); + sg_req[i].csr = csr; + sg_req[i].mmio_seq = mmio_seq; + sg_req[i].mc_seq = mc_seq; sg_req[i].len = len; } @@ -1128,7 +1137,8 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l unsigned long flags) { enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED; - u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0, burst_size; + u32 csr, mc_seq, mmio_seq = 0, burst_size; + dma_addr_t apb_ptr = 0; unsigned int max_dma_count, len, period_count, i; struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); struct tegra_dma_desc *dma_desc; @@ -1186,7 +1196,7 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1); - mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); + mc_seq = tdc_read(tdc, tdc->regs->mc_seq); /* retain stream-id and clean rest */ mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK; @@ -1217,24 +1227,20 @@ tegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_l for (i = 0; i < period_count; i++) { mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len); if (direction == DMA_MEM_TO_DEV) { - sg_req[i].ch_regs.src_ptr = mem; - sg_req[i].ch_regs.dst_ptr = apb_ptr; - sg_req[i].ch_regs.high_addr_ptr = - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32)); + sg_req[i].src = mem; + sg_req[i].dst = apb_ptr; } else if (direction == DMA_DEV_TO_MEM) { - sg_req[i].ch_regs.src_ptr = apb_ptr; - sg_req[i].ch_regs.dst_ptr = mem; - sg_req[i].ch_regs.high_addr_ptr = - FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32)); + sg_req[i].src = apb_ptr; + sg_req[i].dst = mem; } /* * Word count register takes input in words. Writing a value * of N into word count register means a req of (N+1) words. */ - sg_req[i].ch_regs.wcount = ((len - 4) >> 2); - sg_req[i].ch_regs.csr = csr; - sg_req[i].ch_regs.mmio_seq = mmio_seq; - sg_req[i].ch_regs.mc_seq = mc_seq; + sg_req[i].wcount = ((len - 4) >> 2); + sg_req[i].csr = csr; + sg_req[i].mmio_seq = mmio_seq; + sg_req[i].mc_seq = mc_seq; sg_req[i].len = len; mem += len; @@ -1304,27 +1310,76 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec, return chan; } +static const struct tegra_dma_channel_regs tegra186_reg_offsets = { + .csr = 0x0, + .status = 0x4, + .csre = 0x8, + .src = 0xc, + .dst = 0x10, + .high_addr = 0x14, + .mc_seq = 0x18, + .mmio_seq = 0x1c, + .wcount = 0x20, + .wxfer = 0x24, + .wstatus = 0x28, + .err_status = 0x30, + .fixed_pattern = 0x34, +}; + +static const struct tegra_dma_channel_regs tegra264_reg_offsets = { + .csr = 0x0, + .status = 0x4, + .csre = 0x8, + .src = 0xc, + .dst = 0x10, + .src_high = 0x14, + .dst_high = 0x18, + .mc_seq = 0x1c, + .mmio_seq = 0x20, + .wcount = 0x24, + .wxfer = 0x28, + .wstatus = 0x2c, + .err_status = 0x34, + .fixed_pattern = 0x38, +}; + static const struct tegra_dma_chip_data tegra186_dma_chip_data = { .nr_channels = 32, + .addr_bits = 39, .channel_reg_size = SZ_64K, .max_dma_count = SZ_1G, .hw_support_pause = false, + .channel_regs = &tegra186_reg_offsets, .terminate = tegra_dma_stop_client, }; static const struct tegra_dma_chip_data tegra194_dma_chip_data = { .nr_channels = 32, + .addr_bits = 39, .channel_reg_size = SZ_64K, .max_dma_count = SZ_1G, .hw_support_pause = true, + .channel_regs = &tegra186_reg_offsets, .terminate = tegra_dma_pause, }; static const struct tegra_dma_chip_data tegra234_dma_chip_data = { .nr_channels = 32, + .addr_bits = 39, .channel_reg_size = SZ_64K, .max_dma_count = SZ_1G, .hw_support_pause = true, + .channel_regs = &tegra186_reg_offsets, + .terminate = tegra_dma_pause_noerr, +}; + +static const struct tegra_dma_chip_data tegra264_dma_chip_data = { + .nr_channels = 32, + .addr_bits = 41, + .channel_reg_size = SZ_64K, + .max_dma_count = SZ_1G, + .hw_support_pause = true, + .channel_regs = &tegra264_reg_offsets, .terminate = tegra_dma_pause_noerr, }; @@ -1339,13 +1394,16 @@ static const struct of_device_id tegra_dma_of_match[] = { .compatible = "nvidia,tegra234-gpcdma", .data = &tegra234_dma_chip_data, }, { + .compatible = "nvidia,tegra264-gpcdma", + .data = &tegra264_dma_chip_data, + }, { }, }; MODULE_DEVICE_TABLE(of, tegra_dma_of_match); static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id) { - unsigned int reg_val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); + unsigned int reg_val = tdc_read(tdc, tdc->regs->mc_seq); reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK); reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK); @@ -1353,16 +1411,20 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id) reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK, stream_id); reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK, stream_id); - tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, reg_val); + tdc_write(tdc, tdc->regs->mc_seq, reg_val); return 0; } static int tegra_dma_probe(struct platform_device *pdev) { const struct tegra_dma_chip_data *cdata = NULL; + struct tegra_dma_channel *tdc; + struct tegra_dma *tdma; + struct dma_chan *chan; + struct device *chdev; + bool use_iommu_map = false; unsigned int i; u32 stream_id; - struct tegra_dma *tdma; int ret; cdata = of_device_get_match_data(&pdev->dev); @@ -1381,18 +1443,19 @@ static int tegra_dma_probe(struct platform_device *pdev) if (IS_ERR(tdma->base_addr)) return PTR_ERR(tdma->base_addr); - tdma->rst = devm_reset_control_get_exclusive(&pdev->dev, "gpcdma"); + tdma->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, "gpcdma"); if (IS_ERR(tdma->rst)) { return dev_err_probe(&pdev->dev, PTR_ERR(tdma->rst), - "Missing controller reset\n"); + "Failed to get controller reset\n"); } reset_control_reset(tdma->rst); tdma->dma_dev.dev = &pdev->dev; - if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) { - dev_err(&pdev->dev, "Missing iommu stream-id\n"); - return -EINVAL; + use_iommu_map = of_property_present(pdev->dev.of_node, "iommu-map"); + if (!use_iommu_map) { + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) + return dev_err_probe(&pdev->dev, -EINVAL, "Missing iommu stream-id\n"); } ret = device_property_read_u32(&pdev->dev, "dma-channel-mask", @@ -1404,9 +1467,10 @@ static int tegra_dma_probe(struct platform_device *pdev) tdma->chan_mask = TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK; } + /* Initialize vchan for each channel and populate the channels list */ INIT_LIST_HEAD(&tdma->dma_dev.channels); for (i = 0; i < cdata->nr_channels; i++) { - struct tegra_dma_channel *tdc = &tdma->channels[i]; + tdc = &tdma->channels[i]; /* Check for channel mask */ if (!(tdma->chan_mask & BIT(i))) @@ -1419,18 +1483,17 @@ static int tegra_dma_probe(struct platform_device *pdev) tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET + i * cdata->channel_reg_size; snprintf(tdc->name, sizeof(tdc->name), "gpcdma.%d", i); + tdc->regs = cdata->channel_regs; tdc->tdma = tdma; tdc->id = i; tdc->slave_id = -1; vchan_init(&tdc->vc, &tdma->dma_dev); tdc->vc.desc_free = tegra_dma_desc_free; - - /* program stream-id for this channel */ - tegra_dma_program_sid(tdc, stream_id); - tdc->stream_id = stream_id; } + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(cdata->addr_bits)); + dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_MEMCPY, tdma->dma_dev.cap_mask); @@ -1460,37 +1523,59 @@ static int tegra_dma_probe(struct platform_device *pdev) tdma->dma_dev.device_synchronize = tegra_dma_chan_synchronize; tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; - ret = dma_async_device_register(&tdma->dma_dev); + /* Register the DMA device and the channels */ + ret = dmaenginem_async_device_register(&tdma->dma_dev); if (ret < 0) { dev_err_probe(&pdev->dev, ret, "GPC DMA driver registration failed\n"); return ret; } - ret = of_dma_controller_register(pdev->dev.of_node, - tegra_dma_of_xlate, tdma); + /* + * Configure stream ID for each channel from the channels registered + * above. This is done in a separate iteration to ensure that only + * the channels available and registered for the DMA device are used. + */ + list_for_each_entry(chan, &tdma->dma_dev.channels, device_node) { + chdev = &chan->dev->device; + tdc = to_tegra_dma_chan(chan); + + if (use_iommu_map) { + chdev->bus = pdev->dev.bus; + dma_coerce_mask_and_coherent(chdev, DMA_BIT_MASK(cdata->addr_bits)); + + ret = of_dma_configure_id(chdev, pdev->dev.of_node, + true, &tdc->id); + if (ret) + return dev_err_probe(chdev, ret, + "Failed to configure IOMMU for channel %d\n", tdc->id); + + if (!tegra_dev_iommu_get_stream_id(chdev, &stream_id)) + return dev_err_probe(chdev, -EINVAL, + "Failed to get stream ID for channel %d\n", tdc->id); + + chan->dev->chan_dma_dev = true; + } + + /* program stream-id for this channel */ + tegra_dma_program_sid(tdc, stream_id); + tdc->stream_id = stream_id; + } + + ret = devm_of_dma_controller_register(&pdev->dev, pdev->dev.of_node, + tegra_dma_of_xlate, tdma); if (ret < 0) { dev_err_probe(&pdev->dev, ret, "GPC DMA OF registration failed\n"); - - dma_async_device_unregister(&tdma->dma_dev); return ret; } - dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n", + dev_info(&pdev->dev, "GPC DMA driver registered %lu channels\n", hweight_long(tdma->chan_mask)); return 0; } -static void tegra_dma_remove(struct platform_device *pdev) -{ - struct tegra_dma *tdma = platform_get_drvdata(pdev); - - of_dma_controller_free(pdev->dev.of_node); - dma_async_device_unregister(&tdma->dma_dev); -} - static int __maybe_unused tegra_dma_pm_suspend(struct device *dev) { struct tegra_dma *tdma = dev_get_drvdata(dev); @@ -1541,7 +1626,6 @@ static struct platform_driver tegra_dma_driver = { .of_match_table = tegra_dma_of_match, }, .probe = tegra_dma_probe, - .remove = tegra_dma_remove, }; module_platform_driver(tegra_dma_driver); diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 14e0c408ed1e..ceaee1e33e68 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -335,8 +335,16 @@ static int tegra_adma_request_alloc(struct tegra_adma_chan *tdc, struct tegra_adma *tdma = tdc->tdma; unsigned int sreq_index = tdc->sreq_index; - if (tdc->sreq_reserved) - return tdc->sreq_dir == direction ? 0 : -EINVAL; + if (tdc->sreq_reserved) { + if (tdc->sreq_dir != direction) { + dev_err(tdma->dev, + "DMA request direction mismatch: reserved=%s, requested=%s\n", + dmaengine_get_direction_text(tdc->sreq_dir), + dmaengine_get_direction_text(direction)); + return -EINVAL; + } + return 0; + } if (sreq_index > tdma->cdata->ch_req_max) { dev_err(tdma->dev, "invalid DMA request\n"); @@ -665,8 +673,11 @@ static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc, const struct tegra_adma_chip_data *cdata = tdc->tdma->cdata; unsigned int burst_size, adma_dir, fifo_size_shift; - if (desc->num_periods > ADMA_CH_CONFIG_MAX_BUFS) + if (desc->num_periods > ADMA_CH_CONFIG_MAX_BUFS) { + dev_err(tdc2dev(tdc), "invalid DMA periods %zu (max %u)\n", + desc->num_periods, ADMA_CH_CONFIG_MAX_BUFS); return -EINVAL; + } switch (direction) { case DMA_MEM_TO_DEV: @@ -1029,8 +1040,8 @@ static int tegra_adma_probe(struct platform_device *pdev) cdata = of_device_get_match_data(&pdev->dev); if (!cdata) { - dev_err(&pdev->dev, "device match data not found\n"); - return -ENODEV; + return dev_err_probe(&pdev->dev, -ENODEV, + "device match data not found\n"); } tdma = devm_kzalloc(&pdev->dev, @@ -1056,7 +1067,8 @@ static int tegra_adma_probe(struct platform_device *pdev) unsigned int ch_base_offset; if (res_page->start < res_base->start) - return -EINVAL; + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid page/global resource order\n"); page_offset = res_page->start - res_base->start; ch_base_offset = cdata->ch_base_offset; if (!ch_base_offset) @@ -1064,7 +1076,9 @@ static int tegra_adma_probe(struct platform_device *pdev) page_no = div_u64(page_offset, ch_base_offset); if (!page_no || page_no > INT_MAX) - return -EINVAL; + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid page number %llu\n", + (unsigned long long)page_no); tdma->ch_page_no = page_no - 1; tdma->base_addr = devm_ioremap_resource(&pdev->dev, res_base); @@ -1079,7 +1093,8 @@ static int tegra_adma_probe(struct platform_device *pdev) if (IS_ERR(tdma->base_addr)) return PTR_ERR(tdma->base_addr); } else { - return -ENODEV; + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to get memory resource\n"); } tdma->ch_base_addr = tdma->base_addr + cdata->ch_base_offset; @@ -1087,8 +1102,8 @@ static int tegra_adma_probe(struct platform_device *pdev) tdma->ahub_clk = devm_clk_get(&pdev->dev, "d_audio"); if (IS_ERR(tdma->ahub_clk)) { - dev_err(&pdev->dev, "Error: Missing ahub controller clock\n"); - return PTR_ERR(tdma->ahub_clk); + return dev_err_probe(&pdev->dev, PTR_ERR(tdma->ahub_clk), + "failed to get ahub clock\n"); } tdma->dma_chan_mask = devm_kzalloc(&pdev->dev, @@ -1104,8 +1119,8 @@ static int tegra_adma_probe(struct platform_device *pdev) (u32 *)tdma->dma_chan_mask, BITS_TO_U32(tdma->nr_channels)); if (ret < 0 && (ret != -EINVAL)) { - dev_err(&pdev->dev, "dma-channel-mask is not complete.\n"); - return ret; + return dev_err_probe(&pdev->dev, ret, + "dma-channel-mask is not complete.\n"); } INIT_LIST_HEAD(&tdma->dma_dev.channels); @@ -1127,11 +1142,13 @@ static int tegra_adma_probe(struct platform_device *pdev) cdata->global_ch_config_base + (4 * i); } - tdc->irq = of_irq_get(pdev->dev.of_node, i); - if (tdc->irq <= 0) { - ret = tdc->irq ?: -ENXIO; + ret = of_irq_get(pdev->dev.of_node, i); + if (ret <= 0) { + ret = dev_err_probe(&pdev->dev, ret ?: -ENXIO, + "failed to get IRQ for channel %d\n", i); goto irq_dispose; } + tdc->irq = ret; vchan_init(&tdc->vc, &tdma->dma_dev); tdc->vc.desc_free = tegra_adma_desc_free; @@ -1141,12 +1158,18 @@ static int tegra_adma_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) + if (ret < 0) { + ret = dev_err_probe(&pdev->dev, ret, + "runtime PM resume failed\n"); goto rpm_disable; + } ret = tegra_adma_init(tdma); - if (ret) + if (ret) { + ret = dev_err_probe(&pdev->dev, ret, + "failed to initialize ADMA\n"); goto rpm_put; + } dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask); @@ -1172,14 +1195,16 @@ static int tegra_adma_probe(struct platform_device *pdev) ret = dma_async_device_register(&tdma->dma_dev); if (ret < 0) { - dev_err(&pdev->dev, "ADMA registration failed: %d\n", ret); + ret = dev_err_probe(&pdev->dev, ret, + "ADMA registration failed\n"); goto rpm_put; } ret = of_dma_controller_register(pdev->dev.of_node, tegra_dma_of_xlate, tdma); if (ret < 0) { - dev_err(&pdev->dev, "ADMA OF registration failed %d\n", ret); + ret = dev_err_probe(&pdev->dev, ret, + "ADMA OF registration failed\n"); goto dma_remove; } diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 31c543c876b1..971ac83eee90 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -151,6 +151,12 @@ struct rzv2h_hw_info { #define ICU_DMAC_PREP_DMAREQ(sel, up) (FIELD_PREP(ICU_DMAC_DkRQ_SEL_MASK, (sel)) \ << ICU_DMAC_DMAREQ_SHIFT(up)) +/* DMAC ACK routing - 4 x 7-bit fields per 32-bit register, 8-bit spacing */ +#define ICU_DMAC_DACK_SEL_MASK GENMASK(6, 0) +#define ICU_DMAC_DACK_SHIFT(n) ((n) * 8) +#define ICU_DMAC_DACK_FIELD_MASK(n) (ICU_DMAC_DACK_SEL_MASK << ICU_DMAC_DACK_SHIFT(n)) +#define ICU_DMAC_PREP_DACK(val, n) (((val) & ICU_DMAC_DACK_SEL_MASK) << ICU_DMAC_DACK_SHIFT(n)) + /** * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure. * @base: Controller's base address @@ -188,6 +194,40 @@ void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, } EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_req); +/** + * rzv2h_icu_register_dma_ack - Configure DMA ACK signal routing + * @icu_dev: ICU platform device + * @dmac_index: DMAC instance index (0-4) + * @dmac_channel: DMAC channel number (0-15), or RZV2H_ICU_DMAC_ACK_NO_DEFAULT + * to disconnect routing for a given ack_no + * @ack_no: Peripheral ACK number (0-88) per RZ/G3E manual Table 4.6-28, + * used as index into ICU_DMACKSELk + * + * Routes the ACK signal of the peripheral identified by @ack_no to DMAC + * channel @dmac_channel of instance @dmac_index. When @dmac_channel is + * RZV2H_ICU_DMAC_ACK_NO_DEFAULT the field is reset, disconnecting any + * previously configured routing for that peripheral. + */ +void rzv2h_icu_register_dma_ack(struct platform_device *icu_dev, u8 dmac_index, + u8 dmac_channel, u16 ack_no) +{ + struct rzv2h_icu_priv *priv = platform_get_drvdata(icu_dev); + u8 reg_idx = ack_no / 4; + u8 field_idx = ack_no & 0x3; + u8 dmac_ack_src = (dmac_channel == RZV2H_ICU_DMAC_ACK_NO_DEFAULT) ? + RZV2H_ICU_DMAC_ACK_NO_DEFAULT : + (dmac_index * 16 + dmac_channel); + u32 val; + + guard(raw_spinlock_irqsave)(&priv->lock); + + val = readl(priv->base + ICU_DMACKSELk(reg_idx)); + val &= ~ICU_DMAC_DACK_FIELD_MASK(field_idx); + val |= ICU_DMAC_PREP_DACK(dmac_ack_src, field_idx); + writel(val, priv->base + ICU_DMACKSELk(reg_idx)); +} +EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_ack); + static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data) { return data->domain->host_data; |
