dmaengine updates for v5.2-rc1

- Updates to stm32 dma residue calculations
  - Interleave dma capability to axi-dmac and
    support for ZynqMP arch
  - Rework of channel assignment for rcar dma
  - Debugfs for pl330 driver
  - Support for Tegra186/Tegra194, refactoring for new chips
    and support for pause/resume
  - Updates to axi-dmac, bcm2835, fsl-edma, idma64, imx-sdma,
    rcar-dmac, stm32-dma etc
  - dev_get_drvdata() updates on few drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJc08p1AAoJEHwUBw8lI4NHD14QAJGU7MOc9dpr+qtm2k3sNO3o
 EXZtb3GjTs4MUt6EfMA47KXsxeq4UhubQqM7CmPngDyjXaPd4JBE8bwAd+OzS9sq
 eAPMa+M1g8MehuQcdUzB/y6APoSFhGvFoGLY8e7FeI6fwYNm3Yy2gTSiZfpMb3MW
 hclJQe+UWfppUHOig13tr0tbQ31DOa7qb2+roVJqDEb9sQ5bDkhRWXjElfoeSXsS
 n8nNh4GZr5RkIxfzslVRZNfqb1lja2e03SXBsN9faQI7BfIYBM+9hWSYd4Nq8uYo
 xvhYf9gJnKVKtFrwdXtyeBJ80DijWBoodhLrLOfhEYYOrCl9WwJT9AepIOdvij32
 11FwjCbkC9ASQ1cSLyRUBbdmfykSlBvdbAMwJc1y9qK7k9BMba3rXRJfimlRy29A
 Cpsu4tZKoPlZRGinoGnEGreg1YZI1YHwa+hlkW/8V9Zkb2hvIUbbXr7xHedJf7n4
 gIb5DnCF5pC1umB/o7pj2YXrYBc9GETp3sDQ88aw1owKh1T2pZcc5HOpi4p7/7n+
 b2HM0cWOCM3aKwdOcONk0jd87FcYQm3g1isQF5SCOtOys8Uy6wNqo9aRrfE/94aw
 4SiGRq9/nSOHDh72mD3Ux7v47/cFjWGzZZJVy5+NC+Mq79KxgpXOjsIr7YVbcn9m
 GuUdiDZmUvZ4y+qq/uCI
 =JDU6
 -----END PGP SIGNATURE-----

Merge tag 'dmaengine-5.2-rc1' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine updates from Vinod Koul:

 - Updates to stm32 dma residue calculations

 - Interleave dma capability to axi-dmac and support for ZynqMP arch

 - Rework of channel assignment for rcar dma

 - Debugfs for pl330 driver

 - Support for Tegra186/Tegra194, refactoring for new chips and support
   for pause/resume

 - Updates to axi-dmac, bcm2835, fsl-edma, idma64, imx-sdma, rcar-dmac,
   stm32-dma etc

 - dev_get_drvdata() updates on few drivers

* tag 'dmaengine-5.2-rc1' of git://git.infradead.org/users/vkoul/slave-dma: (34 commits)
  dmaengine: tegra210-adma: restore channel status
  dmaengine: tegra210-dma: free dma controller in remove()
  dmaengine: tegra210-adma: add pause/resume support
  dmaengine: tegra210-adma: add support for Tegra186/Tegra194
  Documentation: DT: Add compatibility binding for Tegra186
  dmaengine: tegra210-adma: prepare for supporting newer Tegra chips
  dmaengine: at_xdmac: remove a stray bottom half unlock
  dmaengine: fsl-edma: Adjust indentation
  dmaengine: fsl-edma: Fix typo in Vybrid name
  dmaengine: stm32-dma: fix residue calculation in stm32-dma
  dmaengine: nbpfaxi: Use dev_get_drvdata()
  dmaengine: bcm-sba-raid: Use dev_get_drvdata()
  dmaengine: stm32-dma: Fix unsigned variable compared with zero
  dmaengine: stm32-dma: use platform_get_irq()
  dmaengine: rcar-dmac: Update copyright information
  dmaengine: imx-sdma: Only check ratio on parts that support 1:1
  dmaengine: xgene-dma: fix spelling mistake "descripto" -> "descriptor"
  dmaengine: idma64: Move driver name to the header
  dmaengine: bcm2835: Drop duplicate capability setting.
  dmaengine: pl330: _stop: clear interrupt status
  ...
This commit is contained in:
Linus Torvalds 2019-05-09 08:51:45 -07:00
commit 055128ee00
23 changed files with 566 additions and 169 deletions

View File

@ -18,7 +18,6 @@ Required properties for adi,channels sub-node:
Required channel sub-node properties:
- reg: Which channel this node refers to.
- adi,length-width: Width of the DMA transfer length register.
- adi,source-bus-width,
adi,destination-bus-width: Width of the source or destination bus in bits.
- adi,source-bus-type,
@ -28,7 +27,8 @@ Required channel sub-node properties:
1 (AXI_DMAC_TYPE_AXI_STREAM): Streaming AXI interface
2 (AXI_DMAC_TYPE_AXI_FIFO): FIFO interface
Optional channel properties:
Deprecated optional channel properties:
- adi,length-width: Width of the DMA transfer length register.
- adi,cyclic: Must be set if the channel supports hardware cyclic DMA
transfers.
- adi,2d: Must be set if the channel supports hardware 2D DMA transfers.

View File

@ -4,7 +4,9 @@ The Tegra Audio DMA controller that is used for transferring data
between system memory and the Audio Processing Engine (APE).
Required properties:
- compatible: Must be "nvidia,tegra210-adma".
- compatible: Should contain one of the following:
- "nvidia,tegra210-adma": for Tegra210
- "nvidia,tegra186-adma": for Tegra186 and Tegra194
- reg: Should contain DMA registers location and length. This should be
a single entry that includes all of the per-channel registers in one
contiguous bank.

View File

@ -99,7 +99,7 @@ config AT_XDMAC
config AXI_DMAC
tristate "Analog Devices AXI-DMAC DMA support"
depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_SOCFPGA || COMPILE_TEST
depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_SOCFPGA || COMPILE_TEST
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help

View File

@ -254,6 +254,7 @@ enum pl08x_dma_chan_state {
* @slave: whether this channel is a device (slave) or for memcpy
* @signal: the physical DMA request signal which this channel is using
* @mux_use: count of descriptors using this DMA request signal setting
* @waiting_at: time in jiffies when this channel moved to waiting state
*/
struct pl08x_dma_chan {
struct virt_dma_chan vc;
@ -267,6 +268,7 @@ struct pl08x_dma_chan {
bool slave;
int signal;
unsigned mux_use;
unsigned long waiting_at;
};
/**
@ -875,6 +877,7 @@ static void pl08x_phy_alloc_and_start(struct pl08x_dma_chan *plchan)
if (!ch) {
dev_dbg(&pl08x->adev->dev, "no physical channel available for xfer on %s\n", plchan->name);
plchan->state = PL08X_CHAN_WAITING;
plchan->waiting_at = jiffies;
return;
}
@ -913,22 +916,29 @@ static void pl08x_phy_free(struct pl08x_dma_chan *plchan)
{
struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_dma_chan *p, *next;
unsigned long waiting_at;
retry:
next = NULL;
waiting_at = jiffies;
/* Find a waiting virtual channel for the next transfer. */
/*
* Find a waiting virtual channel for the next transfer.
* To be fair, time when each channel reached waiting state is compared
* to select channel that is waiting for the longest time.
*/
list_for_each_entry(p, &pl08x->memcpy.channels, vc.chan.device_node)
if (p->state == PL08X_CHAN_WAITING) {
if (p->state == PL08X_CHAN_WAITING &&
p->waiting_at <= waiting_at) {
next = p;
break;
waiting_at = p->waiting_at;
}
if (!next && pl08x->has_slave) {
list_for_each_entry(p, &pl08x->slave.channels, vc.chan.device_node)
if (p->state == PL08X_CHAN_WAITING) {
if (p->state == PL08X_CHAN_WAITING &&
p->waiting_at <= waiting_at) {
next = p;
break;
waiting_at = p->waiting_at;
}
}

View File

@ -308,6 +308,11 @@ static inline int at_xdmac_csize(u32 maxburst)
return csize;
};
static inline bool at_xdmac_chan_is_peripheral_xfer(u32 cfg)
{
return cfg & AT_XDMAC_CC_TYPE_PER_TRAN;
}
static inline u8 at_xdmac_get_dwidth(u32 cfg)
{
return (cfg & AT_XDMAC_CC_DWIDTH_MASK) >> AT_XDMAC_CC_DWIDTH_OFFSET;
@ -389,7 +394,13 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
at_xdmac_chan_write(atchan, AT_XDMAC_CID, 0xffffffff);
reg = AT_XDMAC_CIE_RBEIE | AT_XDMAC_CIE_WBEIE | AT_XDMAC_CIE_ROIE;
reg = AT_XDMAC_CIE_RBEIE | AT_XDMAC_CIE_WBEIE;
/*
* Request Overflow Error is only for peripheral synchronized transfers
*/
if (at_xdmac_chan_is_peripheral_xfer(first->lld.mbr_cfg))
reg |= AT_XDMAC_CIE_ROIE;
/*
* There is no end of list when doing cyclic dma, we need to get
* an interrupt after each periods.
@ -1575,6 +1586,46 @@ static void at_xdmac_handle_cyclic(struct at_xdmac_chan *atchan)
dmaengine_desc_get_callback_invoke(txd, NULL);
}
static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
{
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
struct at_xdmac_desc *bad_desc;
/*
* The descriptor currently at the head of the active list is
* broken. Since we don't have any way to report errors, we'll
* just have to scream loudly and try to continue with other
* descriptors queued (if any).
*/
if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
dev_err(chan2dev(&atchan->chan), "read bus error!!!");
if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
dev_err(chan2dev(&atchan->chan), "write bus error!!!");
if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
spin_lock_bh(&atchan->lock);
/* Channel must be disabled first as it's not done automatically */
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
cpu_relax();
bad_desc = list_first_entry(&atchan->xfers_list,
struct at_xdmac_desc,
xfer_node);
spin_unlock_bh(&atchan->lock);
/* Print bad descriptor's details if needed */
dev_dbg(chan2dev(&atchan->chan),
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
__func__, &bad_desc->lld.mbr_sa, &bad_desc->lld.mbr_da,
bad_desc->lld.mbr_ubc);
/* Then continue with usual descriptor management */
}
static void at_xdmac_tasklet(unsigned long data)
{
struct at_xdmac_chan *atchan = (struct at_xdmac_chan *)data;
@ -1594,19 +1645,19 @@ static void at_xdmac_tasklet(unsigned long data)
|| (atchan->irq_status & error_mask)) {
struct dma_async_tx_descriptor *txd;
if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
dev_err(chan2dev(&atchan->chan), "read bus error!!!");
if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
dev_err(chan2dev(&atchan->chan), "write bus error!!!");
if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
if (atchan->irq_status & error_mask)
at_xdmac_handle_error(atchan);
spin_lock(&atchan->lock);
desc = list_first_entry(&atchan->xfers_list,
struct at_xdmac_desc,
xfer_node);
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, desc);
BUG_ON(!desc->active_xfer);
if (!desc->active_xfer) {
dev_err(chan2dev(&atchan->chan), "Xfer not active: exiting");
spin_unlock(&atchan->lock);
return;
}
txd = &desc->tx_dma_desc;

View File

@ -1459,8 +1459,7 @@ static void sba_receive_message(struct mbox_client *cl, void *msg)
static int sba_debugfs_stats_show(struct seq_file *file, void *offset)
{
struct platform_device *pdev = to_platform_device(file->private);
struct sba_device *sba = platform_get_drvdata(pdev);
struct sba_device *sba = dev_get_drvdata(file->private);
/* Write stats in file */
sba_write_stats_in_seqfile(sba, file);

View File

@ -891,7 +891,6 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask);
dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask);
od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources;
od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;

View File

@ -166,7 +166,7 @@ static int axi_dmac_dest_is_mem(struct axi_dmac_chan *chan)
static bool axi_dmac_check_len(struct axi_dmac_chan *chan, unsigned int len)
{
if (len == 0 || len > chan->max_length)
if (len == 0)
return false;
if ((len & chan->align_mask) != 0) /* Not aligned */
return false;
@ -379,6 +379,49 @@ static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs)
return 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,
struct axi_dmac_sg *sg)
{
unsigned int num_segments, i;
unsigned int segment_size;
unsigned int len;
/* Split into multiple equally sized segments if necessary */
num_segments = DIV_ROUND_UP(period_len, chan->max_length);
segment_size = DIV_ROUND_UP(period_len, num_segments);
/* Take care of alignment */
segment_size = ((segment_size - 1) | chan->align_mask) + 1;
for (i = 0; i < num_periods; i++) {
len = period_len;
while (len > segment_size) {
if (direction == DMA_DEV_TO_MEM)
sg->dest_addr = addr;
else
sg->src_addr = addr;
sg->x_len = segment_size;
sg->y_len = 1;
sg++;
addr += segment_size;
len -= segment_size;
}
if (direction == DMA_DEV_TO_MEM)
sg->dest_addr = addr;
else
sg->src_addr = addr;
sg->x_len = len;
sg->y_len = 1;
sg++;
addr += len;
}
return sg;
}
static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
struct dma_chan *c, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@ -386,16 +429,24 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
{
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
struct axi_dmac_desc *desc;
struct axi_dmac_sg *dsg;
struct scatterlist *sg;
unsigned int num_sgs;
unsigned int i;
if (direction != chan->direction)
return NULL;
desc = axi_dmac_alloc_desc(sg_len);
num_sgs = 0;
for_each_sg(sgl, sg, sg_len, i)
num_sgs += DIV_ROUND_UP(sg_dma_len(sg), chan->max_length);
desc = axi_dmac_alloc_desc(num_sgs);
if (!desc)
return NULL;
dsg = desc->sg;
for_each_sg(sgl, sg, sg_len, i) {
if (!axi_dmac_check_addr(chan, sg_dma_address(sg)) ||
!axi_dmac_check_len(chan, sg_dma_len(sg))) {
@ -403,12 +454,8 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
return NULL;
}
if (direction == DMA_DEV_TO_MEM)
desc->sg[i].dest_addr = sg_dma_address(sg);
else
desc->sg[i].src_addr = sg_dma_address(sg);
desc->sg[i].x_len = sg_dma_len(sg);
desc->sg[i].y_len = 1;
dsg = axi_dmac_fill_linear_sg(chan, direction, sg_dma_address(sg), 1,
sg_dma_len(sg), dsg);
}
desc->cyclic = false;
@ -423,7 +470,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
{
struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
struct axi_dmac_desc *desc;
unsigned int num_periods, i;
unsigned int num_periods, num_segments;
if (direction != chan->direction)
return NULL;
@ -436,20 +483,14 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic(
return NULL;
num_periods = buf_len / period_len;
num_segments = DIV_ROUND_UP(period_len, chan->max_length);
desc = axi_dmac_alloc_desc(num_periods);
desc = axi_dmac_alloc_desc(num_periods * num_segments);
if (!desc)
return NULL;
for (i = 0; i < num_periods; i++) {
if (direction == DMA_DEV_TO_MEM)
desc->sg[i].dest_addr = buf_addr;
else
desc->sg[i].src_addr = buf_addr;
desc->sg[i].x_len = period_len;
desc->sg[i].y_len = 1;
buf_addr += period_len;
}
axi_dmac_fill_linear_sg(chan, direction, buf_addr, num_periods,
period_len, desc->sg);
desc->cyclic = true;
@ -485,7 +526,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved(
if (chan->hw_2d) {
if (!axi_dmac_check_len(chan, xt->sgl[0].size) ||
!axi_dmac_check_len(chan, xt->numf))
xt->numf == 0)
return NULL;
if (xt->sgl[0].size + dst_icg > chan->max_length ||
xt->sgl[0].size + src_icg > chan->max_length)
@ -577,15 +618,6 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
return ret;
chan->dest_width = val / 8;
ret = of_property_read_u32(of_chan, "adi,length-width", &val);
if (ret)
return ret;
if (val >= 32)
chan->max_length = UINT_MAX;
else
chan->max_length = (1ULL << val) - 1;
chan->align_mask = max(chan->dest_width, chan->src_width) - 1;
if (axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan))
@ -597,12 +629,27 @@ static int axi_dmac_parse_chan_dt(struct device_node *of_chan,
else
chan->direction = DMA_DEV_TO_DEV;
chan->hw_cyclic = of_property_read_bool(of_chan, "adi,cyclic");
chan->hw_2d = of_property_read_bool(of_chan, "adi,2d");
return 0;
}
static void axi_dmac_detect_caps(struct axi_dmac *dmac)
{
struct axi_dmac_chan *chan = &dmac->chan;
axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC);
if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC)
chan->hw_cyclic = true;
axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 1);
if (axi_dmac_read(dmac, AXI_DMAC_REG_Y_LENGTH) == 1)
chan->hw_2d = true;
axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, 0xffffffff);
chan->max_length = axi_dmac_read(dmac, AXI_DMAC_REG_X_LENGTH);
if (chan->max_length != UINT_MAX)
chan->max_length++;
}
static int axi_dmac_probe(struct platform_device *pdev)
{
struct device_node *of_channels, *of_chan;
@ -647,11 +694,12 @@ static int axi_dmac_probe(struct platform_device *pdev)
of_node_put(of_channels);
pdev->dev.dma_parms = &dmac->dma_parms;
dma_set_max_seg_size(&pdev->dev, dmac->chan.max_length);
dma_set_max_seg_size(&pdev->dev, UINT_MAX);
dma_dev = &dmac->dma_dev;
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_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;
@ -675,6 +723,8 @@ static int axi_dmac_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
axi_dmac_detect_caps(dmac);
axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00);
ret = dma_async_device_register(dma_dev);

View File

@ -136,7 +136,7 @@ struct fsl_edma_desc {
};
enum edma_version {
v1, /* 32ch, Vybdir, mpc57x, etc */
v1, /* 32ch, Vybrid, mpc57x, etc */
v2, /* 64ch Coldfire */
};

View File

@ -144,21 +144,21 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma
fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
if (ret) {
dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
return ret;
return ret;
}
} else {
ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
if (ret) {
dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
return ret;
return ret;
}
ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
if (ret) {
dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
return ret;
return ret;
}
}

View File

@ -19,10 +19,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "idma64.h"
#include <linux/dma/idma64.h>
/* Platform driver name */
#define DRV_NAME "idma64"
#include "idma64.h"
/* For now we support only two channels */
#define IDMA64_NR_CHAN 2
@ -592,7 +591,7 @@ static int idma64_probe(struct idma64_chip *chip)
idma64->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
idma64->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
idma64->dma.dev = chip->dev;
idma64->dma.dev = chip->sysdev;
dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK);
@ -632,6 +631,7 @@ static int idma64_platform_probe(struct platform_device *pdev)
{
struct idma64_chip *chip;
struct device *dev = &pdev->dev;
struct device *sysdev = dev->parent;
struct resource *mem;
int ret;
@ -648,11 +648,12 @@ static int idma64_platform_probe(struct platform_device *pdev)
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
if (ret)
return ret;
chip->dev = dev;
chip->sysdev = sysdev;
ret = idma64_probe(chip);
if (ret)
@ -697,7 +698,7 @@ static struct platform_driver idma64_platform_driver = {
.probe = idma64_platform_probe,
.remove = idma64_platform_remove,
.driver = {
.name = DRV_NAME,
.name = LPSS_IDMA64_DRIVER_NAME,
.pm = &idma64_dev_pm_ops,
},
};
@ -707,4 +708,4 @@ module_platform_driver(idma64_platform_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("iDMA64 core driver");
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_ALIAS("platform:" LPSS_IDMA64_DRIVER_NAME);

View File

@ -216,12 +216,14 @@ static inline void idma64_writel(struct idma64 *idma64, int offset, u32 value)
/**
* struct idma64_chip - representation of iDMA 64-bit controller hardware
* @dev: struct device of the DMA controller
* @sysdev: struct device of the physical device that does DMA
* @irq: irq line
* @regs: memory mapped I/O space
* @idma64: struct idma64 that is filed by idma64_probe()
*/
struct idma64_chip {
struct device *dev;
struct device *sysdev;
int irq;
void __iomem *regs;
struct idma64 *idma64;

View File

@ -419,6 +419,7 @@ struct sdma_driver_data {
int chnenbl0;
int num_events;
struct sdma_script_start_addrs *script_addrs;
bool check_ratio;
};
struct sdma_engine {
@ -557,6 +558,13 @@ static struct sdma_driver_data sdma_imx7d = {
.script_addrs = &sdma_script_imx7d,
};
static struct sdma_driver_data sdma_imx8mq = {
.chnenbl0 = SDMA_CHNENBL0_IMX35,
.num_events = 48,
.script_addrs = &sdma_script_imx7d,
.check_ratio = 1,
};
static const struct platform_device_id sdma_devtypes[] = {
{
.name = "imx25-sdma",
@ -579,6 +587,9 @@ static const struct platform_device_id sdma_devtypes[] = {
}, {
.name = "imx7d-sdma",
.driver_data = (unsigned long)&sdma_imx7d,
}, {
.name = "imx8mq-sdma",
.driver_data = (unsigned long)&sdma_imx8mq,
}, {
/* sentinel */
}
@ -593,6 +604,7 @@ static const struct of_device_id sdma_dt_ids[] = {
{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
{ .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
{ .compatible = "fsl,imx8mq-sdma", .data = &sdma_imx8mq, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdma_dt_ids);
@ -1852,7 +1864,8 @@ static int sdma_init(struct sdma_engine *sdma)
if (ret)
goto disable_clk_ipg;
if (clk_get_rate(sdma->clk_ahb) == clk_get_rate(sdma->clk_ipg))
if (sdma->drvdata->check_ratio &&
(clk_get_rate(sdma->clk_ahb) == clk_get_rate(sdma->clk_ipg)))
sdma->clk_ratio = 1;
/* Be sure SDMA has not started yet */

View File

@ -1491,14 +1491,14 @@ MODULE_DEVICE_TABLE(platform, nbpf_ids);
#ifdef CONFIG_PM
static int nbpf_runtime_suspend(struct device *dev)
{
struct nbpf_device *nbpf = platform_get_drvdata(to_platform_device(dev));
struct nbpf_device *nbpf = dev_get_drvdata(dev);
clk_disable_unprepare(nbpf->clk);
return 0;
}
static int nbpf_runtime_resume(struct device *dev)
{
struct nbpf_device *nbpf = platform_get_drvdata(to_platform_device(dev));
struct nbpf_device *nbpf = dev_get_drvdata(dev);
return clk_prepare_enable(nbpf->clk);
}
#endif

View File

@ -11,6 +11,7 @@
* (at your option) any later version.
*/
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/init.h>
@ -966,6 +967,7 @@ static void _stop(struct pl330_thread *thrd)
{
void __iomem *regs = thrd->dmac->base;
u8 insn[6] = {0, 0, 0, 0, 0, 0};
u32 inten = readl(regs + INTEN);
if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
@ -978,10 +980,13 @@ static void _stop(struct pl330_thread *thrd)
_emit_KILL(0, insn);
/* Stop generating interrupts for SEV */
writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN);
_execute_DBGINSN(thrd, insn, is_manager(thrd));
/* clear the event */
if (inten & (1 << thrd->ev))
writel(1 << thrd->ev, regs + INTCLR);
/* Stop generating interrupts for SEV */
writel(inten & ~(1 << thrd->ev), regs + INTEN);
}
/* Start doing req 'idx' of thread 'thrd' */
@ -2896,6 +2901,55 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
#ifdef CONFIG_DEBUG_FS
static int pl330_debugfs_show(struct seq_file *s, void *data)
{
struct pl330_dmac *pl330 = s->private;
int chans, pchs, ch, pr;
chans = pl330->pcfg.num_chan;
pchs = pl330->num_peripherals;
seq_puts(s, "PL330 physical channels:\n");
seq_puts(s, "THREAD:\t\tCHANNEL:\n");
seq_puts(s, "--------\t-----\n");
for (ch = 0; ch < chans; ch++) {
struct pl330_thread *thrd = &pl330->channels[ch];
int found = -1;
for (pr = 0; pr < pchs; pr++) {
struct dma_pl330_chan *pch = &pl330->peripherals[pr];
if (!pch->thread || thrd->id != pch->thread->id)
continue;
found = pr;
}
seq_printf(s, "%d\t\t", thrd->id);
if (found == -1)
seq_puts(s, "--\n");
else
seq_printf(s, "%d\n", found);
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(pl330_debugfs);
static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
{
debugfs_create_file(dev_name(pl330->ddma.dev),
S_IFREG | 0444, NULL, pl330,
&pl330_debugfs_fops);
}
#else
static inline void init_pl330_debugfs(struct pl330_dmac *pl330)
{
}
#endif
/*
* Runtime PM callbacks are provided by amba/bus.c driver.
*
@ -3082,6 +3136,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
dev_err(&adev->dev, "unable to set the seg size\n");
init_pl330_debugfs(pl330);
dev_info(&adev->dev,
"Loaded driver for PL330 DMAC-%x\n", adev->periphid);
dev_info(&adev->dev,

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Renesas R-Car Gen2 DMA Controller Driver
* Renesas R-Car Gen2/Gen3 DMA Controller Driver
*
* Copyright (C) 2014 Renesas Electronics Inc.
* Copyright (C) 2014-2019 Renesas Electronics Inc.
*
* Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/

View File

@ -1042,33 +1042,97 @@ static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan)
return ndtr << width;
}
/**
* stm32_dma_is_current_sg - check that expected sg_req is currently transferred
* @chan: dma channel
*
* This function called when IRQ are disable, checks that the hardware has not
* switched on the next transfer in double buffer mode. The test is done by
* comparing the next_sg memory address with the hardware related register
* (based on CT bit value).
*
* Returns true if expected current transfer is still running or double
* buffer mode is not activated.
*/
static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan)
{
struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
struct stm32_dma_sg_req *sg_req;
u32 dma_scr, dma_smar, id;
id = chan->id;
dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
if (!(dma_scr & STM32_DMA_SCR_DBM))
return true;
sg_req = &chan->desc->sg_req[chan->next_sg];
if (dma_scr & STM32_DMA_SCR_CT) {
dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id));
return (dma_smar == sg_req->chan_reg.dma_sm0ar);
}
dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id));
return (dma_smar == sg_req->chan_reg.dma_sm1ar);
}
static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
struct stm32_dma_desc *desc,
u32 next_sg)
{
u32 modulo, burst_size;
u32 residue = 0;
u32 residue;
u32 n_sg = next_sg;
struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg];
int i;
/*
* In cyclic mode, for the last period, residue = remaining bytes from
* NDTR
* Calculate the residue means compute the descriptors
* information:
* - the sg_req currently transferred
* - the Hardware remaining position in this sg (NDTR bits field).
*
* A race condition may occur if DMA is running in cyclic or double
* buffer mode, since the DMA register are automatically reloaded at end
* of period transfer. The hardware may have switched to the next
* transfer (CT bit updated) just before the position (SxNDTR reg) is
* read.
* In this case the SxNDTR reg could (or not) correspond to the new
* transfer position, and not the expected one.
* The strategy implemented in the stm32 driver is to:
* - read the SxNDTR register
* - crosscheck that hardware is still in current transfer.
* In case of switch, we can assume that the DMA is at the beginning of
* the next transfer. So we approximate the residue in consequence, by
* pointing on the beginning of next transfer.
*
* This race condition doesn't apply for none cyclic mode, as double
* buffer is not used. In such situation registers are updated by the
* software.
*/
if (chan->desc->cyclic && next_sg == 0) {
residue = stm32_dma_get_remaining_bytes(chan);
goto end;
residue = stm32_dma_get_remaining_bytes(chan);
if (!stm32_dma_is_current_sg(chan)) {
n_sg++;
if (n_sg == chan->desc->num_sgs)
n_sg = 0;
residue = sg_req->len;
}
/*
* For all other periods in cyclic mode, and in sg mode,
* residue = remaining bytes from NDTR + remaining periods/sg to be
* transferred
* In cyclic mode, for the last period, residue = remaining bytes
* from NDTR,
* else for all other periods in cyclic mode, and in sg mode,
* residue = remaining bytes from NDTR + remaining
* periods/sg to be transferred
*/
for (i = next_sg; i < desc->num_sgs; i++)
residue += desc->sg_req[i].len;
residue += stm32_dma_get_remaining_bytes(chan);
if (!chan->desc->cyclic || n_sg != 0)
for (i = n_sg; i < desc->num_sgs; i++)
residue += desc->sg_req[i].len;
end:
if (!chan->mem_burst)
return residue;
@ -1302,13 +1366,16 @@ static int stm32_dma_probe(struct platform_device *pdev)
for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
chan = &dmadev->chan[i];
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!res) {
ret = -EINVAL;
dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
chan->irq = platform_get_irq(pdev, i);
ret = platform_get_irq(pdev, i);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"No irq resource for chan %d\n", i);
goto err_unregister;
}
chan->irq = res->start;
chan->irq = ret;
ret = devm_request_irq(&pdev->dev, chan->irq,
stm32_dma_chan_irq, 0,
dev_name(chan2dev(chan)), chan);

View File

@ -22,7 +22,6 @@
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/of_irq.h>
#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
@ -31,35 +30,33 @@
#define ADMA_CH_CMD 0x00
#define ADMA_CH_STATUS 0x0c
#define ADMA_CH_STATUS_XFER_EN BIT(0)
#define ADMA_CH_STATUS_XFER_PAUSED BIT(1)
#define ADMA_CH_INT_STATUS 0x10
#define ADMA_CH_INT_STATUS_XFER_DONE BIT(0)
#define ADMA_CH_INT_CLEAR 0x1c
#define ADMA_CH_CTRL 0x24
#define ADMA_CH_CTRL_TX_REQ(val) (((val) & 0xf) << 28)
#define ADMA_CH_CTRL_TX_REQ_MAX 10
#define ADMA_CH_CTRL_RX_REQ(val) (((val) & 0xf) << 24)
#define ADMA_CH_CTRL_RX_REQ_MAX 10
#define ADMA_CH_CTRL_DIR(val) (((val) & 0xf) << 12)
#define ADMA_CH_CTRL_DIR_AHUB2MEM 2
#define ADMA_CH_CTRL_DIR_MEM2AHUB 4
#define ADMA_CH_CTRL_MODE_CONTINUOUS (2 << 8)
#define ADMA_CH_CTRL_FLOWCTRL_EN BIT(1)
#define ADMA_CH_CTRL_XFER_PAUSE_SHIFT 0
#define ADMA_CH_CONFIG 0x28
#define ADMA_CH_CONFIG_SRC_BUF(val) (((val) & 0x7) << 28)
#define ADMA_CH_CONFIG_TRG_BUF(val) (((val) & 0x7) << 24)
#define ADMA_CH_CONFIG_BURST_SIZE(val) (((val) & 0x7) << 20)
#define ADMA_CH_CONFIG_BURST_16 5
#define ADMA_CH_CONFIG_BURST_SIZE_SHIFT 20
#define ADMA_CH_CONFIG_MAX_BURST_SIZE 16
#define ADMA_CH_CONFIG_WEIGHT_FOR_WRR(val) ((val) & 0xf)
#define ADMA_CH_CONFIG_MAX_BUFS 8
#define ADMA_CH_FIFO_CTRL 0x2c
#define ADMA_CH_FIFO_CTRL_OVRFW_THRES(val) (((val) & 0xf) << 24)
#define ADMA_CH_FIFO_CTRL_STARV_THRES(val) (((val) & 0xf) << 16)
#define ADMA_CH_FIFO_CTRL_TX_SIZE(val) (((val) & 0xf) << 8)
#define ADMA_CH_FIFO_CTRL_RX_SIZE(val) ((val) & 0xf)
#define ADMA_CH_FIFO_CTRL_TX_FIFO_SIZE_SHIFT 8
#define ADMA_CH_FIFO_CTRL_RX_FIFO_SIZE_SHIFT 0
#define ADMA_CH_LOWER_SRC_ADDR 0x34
#define ADMA_CH_LOWER_TRG_ADDR 0x3c
@ -69,25 +66,41 @@
#define ADMA_CH_XFER_STATUS 0x54
#define ADMA_CH_XFER_STATUS_COUNT_MASK 0xffff
#define ADMA_GLOBAL_CMD 0xc00
#define ADMA_GLOBAL_SOFT_RESET 0xc04
#define ADMA_GLOBAL_INT_CLEAR 0xc20
#define ADMA_GLOBAL_CTRL 0xc24
#define ADMA_GLOBAL_CMD 0x00
#define ADMA_GLOBAL_SOFT_RESET 0x04
#define ADMA_CH_REG_OFFSET(a) (a * 0x80)
#define TEGRA_ADMA_BURST_COMPLETE_TIME 20
#define ADMA_CH_FIFO_CTRL_DEFAULT (ADMA_CH_FIFO_CTRL_OVRFW_THRES(1) | \
ADMA_CH_FIFO_CTRL_STARV_THRES(1) | \
ADMA_CH_FIFO_CTRL_TX_SIZE(3) | \
ADMA_CH_FIFO_CTRL_RX_SIZE(3))
ADMA_CH_FIFO_CTRL_STARV_THRES(1))
#define ADMA_CH_REG_FIELD_VAL(val, mask, shift) (((val) & mask) << shift)
struct tegra_adma;
/*
* struct tegra_adma_chip_data - Tegra chip specific data
* @global_reg_offset: Register offset of DMA global register.
* @global_int_clear: Register offset of DMA global interrupt clear.
* @ch_req_tx_shift: Register offset for AHUB transmit channel select.
* @ch_req_rx_shift: Register offset for AHUB receive channel select.
* @ch_base_offset: Reister offset of DMA channel registers.
* @ch_req_mask: Mask for Tx or Rx channel select.
* @ch_req_max: Maximum number of Tx or Rx channels available.
* @ch_reg_size: Size of DMA channel register space.
* @nr_channels: Number of DMA channels available.
*/
struct tegra_adma_chip_data {
int nr_channels;
unsigned int (*adma_get_burst_config)(unsigned int burst_size);
unsigned int global_reg_offset;
unsigned int global_int_clear;
unsigned int ch_req_tx_shift;
unsigned int ch_req_rx_shift;
unsigned int ch_base_offset;
unsigned int ch_req_mask;
unsigned int ch_req_max;
unsigned int ch_reg_size;
unsigned int nr_channels;
};
/*
@ -99,6 +112,7 @@ struct tegra_adma_chan_regs {
unsigned int src_addr;
unsigned int trg_addr;
unsigned int fifo_ctrl;
unsigned int cmd;
unsigned int tc;
};
@ -128,6 +142,7 @@ struct tegra_adma_chan {
enum dma_transfer_direction sreq_dir;
unsigned int sreq_index;
bool sreq_reserved;
struct tegra_adma_chan_regs ch_regs;
/* Transfer count and position info */
unsigned int tx_buf_count;
@ -141,6 +156,7 @@ struct tegra_adma {
struct dma_device dma_dev;
struct device *dev;
void __iomem *base_addr;
struct clk *ahub_clk;
unsigned int nr_channels;
unsigned long rx_requests_reserved;
unsigned long tx_requests_reserved;
@ -148,18 +164,20 @@ struct tegra_adma {
/* Used to store global command register state when suspending */
unsigned int global_cmd;
const struct tegra_adma_chip_data *cdata;
/* Last member of the structure */
struct tegra_adma_chan channels[0];
};
static inline void tdma_write(struct tegra_adma *tdma, u32 reg, u32 val)
{
writel(val, tdma->base_addr + reg);
writel(val, tdma->base_addr + tdma->cdata->global_reg_offset + reg);
}
static inline u32 tdma_read(struct tegra_adma *tdma, u32 reg)
{
return readl(tdma->base_addr + reg);
return readl(tdma->base_addr + tdma->cdata->global_reg_offset + reg);
}
static inline void tdma_ch_write(struct tegra_adma_chan *tdc, u32 reg, u32 val)
@ -209,14 +227,16 @@ static int tegra_adma_init(struct tegra_adma *tdma)
int ret;
/* Clear any interrupts */
tdma_write(tdma, ADMA_GLOBAL_INT_CLEAR, 0x1);
tdma_write(tdma, tdma->cdata->global_int_clear, 0x1);
/* Assert soft reset */
tdma_write(tdma, ADMA_GLOBAL_SOFT_RESET, 0x1);
/* Wait for reset to clear */
ret = readx_poll_timeout(readl,
tdma->base_addr + ADMA_GLOBAL_SOFT_RESET,
tdma->base_addr +
tdma->cdata->global_reg_offset +
ADMA_GLOBAL_SOFT_RESET,
status, status == 0, 20, 10000);
if (ret)
return ret;
@ -236,13 +256,13 @@ static int tegra_adma_request_alloc(struct tegra_adma_chan *tdc,
if (tdc->sreq_reserved)
return tdc->sreq_dir == direction ? 0 : -EINVAL;
if (sreq_index > tdma->cdata->ch_req_max) {
dev_err(tdma->dev, "invalid DMA request\n");
return -EINVAL;
}
switch (direction) {
case DMA_MEM_TO_DEV:
if (sreq_index > ADMA_CH_CTRL_TX_REQ_MAX) {
dev_err(tdma->dev, "invalid DMA request\n");
return -EINVAL;
}
if (test_and_set_bit(sreq_index, &tdma->tx_requests_reserved)) {
dev_err(tdma->dev, "DMA request reserved\n");
return -EINVAL;
@ -250,11 +270,6 @@ static int tegra_adma_request_alloc(struct tegra_adma_chan *tdc,
break;
case DMA_DEV_TO_MEM:
if (sreq_index > ADMA_CH_CTRL_RX_REQ_MAX) {
dev_err(tdma->dev, "invalid DMA request\n");
return -EINVAL;
}
if (test_and_set_bit(sreq_index, &tdma->rx_requests_reserved)) {
dev_err(tdma->dev, "DMA request reserved\n");
return -EINVAL;
@ -428,6 +443,51 @@ static void tegra_adma_issue_pending(struct dma_chan *dc)
spin_unlock_irqrestore(&tdc->vc.lock, flags);
}
static bool tegra_adma_is_paused(struct tegra_adma_chan *tdc)
{
u32 csts;
csts = tdma_ch_read(tdc, ADMA_CH_STATUS);
csts &= ADMA_CH_STATUS_XFER_PAUSED;
return csts ? true : false;
}
static int tegra_adma_pause(struct dma_chan *dc)
{
struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc);
struct tegra_adma_desc *desc = tdc->desc;
struct tegra_adma_chan_regs *ch_regs = &desc->ch_regs;
int dcnt = 10;
ch_regs->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL);
ch_regs->ctrl |= (1 << ADMA_CH_CTRL_XFER_PAUSE_SHIFT);
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_regs->ctrl);
while (dcnt-- && !tegra_adma_is_paused(tdc))
udelay(TEGRA_ADMA_BURST_COMPLETE_TIME);
if (dcnt < 0) {
dev_err(tdc2dev(tdc), "unable to pause DMA channel\n");
return -EBUSY;
}
return 0;
}
static int tegra_adma_resume(struct dma_chan *dc)
{
struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc);
struct tegra_adma_desc *desc = tdc->desc;
struct tegra_adma_chan_regs *ch_regs = &desc->ch_regs;
ch_regs->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL);
ch_regs->ctrl &= ~(1 << ADMA_CH_CTRL_XFER_PAUSE_SHIFT);
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_regs->ctrl);
return 0;
}
static int tegra_adma_terminate_all(struct dma_chan *dc)
{
struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc);
@ -481,12 +541,29 @@ static enum dma_status tegra_adma_tx_status(struct dma_chan *dc,
return ret;
}
static unsigned int tegra210_adma_get_burst_config(unsigned int burst_size)
{
if (!burst_size || burst_size > ADMA_CH_CONFIG_MAX_BURST_SIZE)
burst_size = ADMA_CH_CONFIG_MAX_BURST_SIZE;
return fls(burst_size) << ADMA_CH_CONFIG_BURST_SIZE_SHIFT;
}
static unsigned int tegra186_adma_get_burst_config(unsigned int burst_size)
{
if (!burst_size || burst_size > ADMA_CH_CONFIG_MAX_BURST_SIZE)
burst_size = ADMA_CH_CONFIG_MAX_BURST_SIZE;
return (burst_size - 1) << ADMA_CH_CONFIG_BURST_SIZE_SHIFT;
}
static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
struct tegra_adma_desc *desc,
dma_addr_t buf_addr,
enum dma_transfer_direction direction)
{
struct tegra_adma_chan_regs *ch_regs = &desc->ch_regs;
const struct tegra_adma_chip_data *cdata = tdc->tdma->cdata;
unsigned int burst_size, adma_dir;
if (desc->num_periods > ADMA_CH_CONFIG_MAX_BUFS)
@ -495,17 +572,21 @@ static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
switch (direction) {
case DMA_MEM_TO_DEV:
adma_dir = ADMA_CH_CTRL_DIR_MEM2AHUB;
burst_size = fls(tdc->sconfig.dst_maxburst);
burst_size = tdc->sconfig.dst_maxburst;
ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(desc->num_periods - 1);
ch_regs->ctrl = ADMA_CH_CTRL_TX_REQ(tdc->sreq_index);
ch_regs->ctrl = ADMA_CH_REG_FIELD_VAL(tdc->sreq_index,
cdata->ch_req_mask,
cdata->ch_req_tx_shift);
ch_regs->src_addr = buf_addr;
break;
case DMA_DEV_TO_MEM:
adma_dir = ADMA_CH_CTRL_DIR_AHUB2MEM;
burst_size = fls(tdc->sconfig.src_maxburst);
burst_size = tdc->sconfig.src_maxburst;
ch_regs->config = ADMA_CH_CONFIG_TRG_BUF(desc->num_periods - 1);
ch_regs->ctrl = ADMA_CH_CTRL_RX_REQ(tdc->sreq_index);
ch_regs->ctrl = ADMA_CH_REG_FIELD_VAL(tdc->sreq_index,
cdata->ch_req_mask,
cdata->ch_req_rx_shift);
ch_regs->trg_addr = buf_addr;
break;
@ -514,13 +595,10 @@ static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
return -EINVAL;
}
if (!burst_size || burst_size > ADMA_CH_CONFIG_BURST_16)
burst_size = ADMA_CH_CONFIG_BURST_16;
ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir) |
ADMA_CH_CTRL_MODE_CONTINUOUS |
ADMA_CH_CTRL_FLOWCTRL_EN;
ch_regs->config |= ADMA_CH_CONFIG_BURST_SIZE(burst_size);
ch_regs->config |= cdata->adma_get_burst_config(burst_size);
ch_regs->config |= ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1);
ch_regs->fifo_ctrl = ADMA_CH_FIFO_CTRL_DEFAULT;
ch_regs->tc = desc->period_len & ADMA_CH_TC_COUNT_MASK;
@ -635,32 +713,99 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
static int tegra_adma_runtime_suspend(struct device *dev)
{
struct tegra_adma *tdma = dev_get_drvdata(dev);
struct tegra_adma_chan_regs *ch_reg;
struct tegra_adma_chan *tdc;
int i;
tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD);
if (!tdma->global_cmd)
goto clk_disable;
return pm_clk_suspend(dev);
for (i = 0; i < tdma->nr_channels; i++) {
tdc = &tdma->channels[i];
ch_reg = &tdc->ch_regs;
ch_reg->cmd = tdma_ch_read(tdc, ADMA_CH_CMD);
/* skip if channel is not active */
if (!ch_reg->cmd)
continue;
ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC);
ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR);
ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR);
ch_reg->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL);
ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL);
ch_reg->config = tdma_ch_read(tdc, ADMA_CH_CONFIG);
}
clk_disable:
clk_disable_unprepare(tdma->ahub_clk);
return 0;
}
static int tegra_adma_runtime_resume(struct device *dev)
{
struct tegra_adma *tdma = dev_get_drvdata(dev);
int ret;
struct tegra_adma_chan_regs *ch_reg;
struct tegra_adma_chan *tdc;
int ret, i;
ret = pm_clk_resume(dev);
if (ret)
ret = clk_prepare_enable(tdma->ahub_clk);
if (ret) {
dev_err(dev, "ahub clk_enable failed: %d\n", ret);
return ret;
}
tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd);
if (!tdma->global_cmd)
return 0;
for (i = 0; i < tdma->nr_channels; i++) {
tdc = &tdma->channels[i];
ch_reg = &tdc->ch_regs;
/* skip if channel was not active earlier */
if (!ch_reg->cmd)
continue;
tdma_ch_write(tdc, ADMA_CH_TC, ch_reg->tc);
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_reg->src_addr);
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_reg->trg_addr);
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_reg->ctrl);
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl);
tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_reg->config);
tdma_ch_write(tdc, ADMA_CH_CMD, ch_reg->cmd);
}
return 0;
}
static const struct tegra_adma_chip_data tegra210_chip_data = {
.nr_channels = 22,
.adma_get_burst_config = tegra210_adma_get_burst_config,
.global_reg_offset = 0xc00,
.global_int_clear = 0x20,
.ch_req_tx_shift = 28,
.ch_req_rx_shift = 24,
.ch_base_offset = 0,
.ch_req_mask = 0xf,
.ch_req_max = 10,
.ch_reg_size = 0x80,
.nr_channels = 22,
};
static const struct tegra_adma_chip_data tegra186_chip_data = {
.adma_get_burst_config = tegra186_adma_get_burst_config,
.global_reg_offset = 0,
.global_int_clear = 0x402c,
.ch_req_tx_shift = 27,
.ch_req_rx_shift = 22,
.ch_base_offset = 0x10000,
.ch_req_mask = 0x1f,
.ch_req_max = 20,
.ch_reg_size = 0x100,
.nr_channels = 32,
};
static const struct of_device_id tegra_adma_of_match[] = {
{ .compatible = "nvidia,tegra210-adma", .data = &tegra210_chip_data },
{ .compatible = "nvidia,tegra186-adma", .data = &tegra186_chip_data },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_adma_of_match);
@ -685,6 +830,7 @@ static int tegra_adma_probe(struct platform_device *pdev)
return -ENOMEM;
tdma->dev = &pdev->dev;
tdma->cdata = cdata;
tdma->nr_channels = cdata->nr_channels;
platform_set_drvdata(pdev, tdma);
@ -693,13 +839,11 @@ static int tegra_adma_probe(struct platform_device *pdev)
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
ret = pm_clk_create(&pdev->dev);
if (ret)
return ret;
ret = of_pm_clk_add_clk(&pdev->dev, "d_audio");
if (ret)
goto clk_destroy;
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);
}
pm_runtime_enable(&pdev->dev);
@ -715,7 +859,8 @@ static int tegra_adma_probe(struct platform_device *pdev)
for (i = 0; i < tdma->nr_channels; i++) {
struct tegra_adma_chan *tdc = &tdma->channels[i];
tdc->chan_addr = tdma->base_addr + ADMA_CH_REG_OFFSET(i);
tdc->chan_addr = tdma->base_addr + cdata->ch_base_offset
+ (cdata->ch_reg_size * i);
tdc->irq = of_irq_get(pdev->dev.of_node, i);
if (tdc->irq <= 0) {
@ -746,6 +891,8 @@ static int tegra_adma_probe(struct platform_device *pdev)
tdma->dma_dev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
tdma->dma_dev.device_pause = tegra_adma_pause;
tdma->dma_dev.device_resume = tegra_adma_resume;
ret = dma_async_device_register(&tdma->dma_dev);
if (ret < 0) {
@ -776,8 +923,6 @@ static int tegra_adma_probe(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
rpm_disable:
pm_runtime_disable(&pdev->dev);
clk_destroy:
pm_clk_destroy(&pdev->dev);
return ret;
}
@ -787,6 +932,7 @@ static int tegra_adma_remove(struct platform_device *pdev)
struct tegra_adma *tdma = platform_get_drvdata(pdev);
int i;
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&tdma->dma_dev);
for (i = 0; i < tdma->nr_channels; ++i)
@ -794,22 +940,15 @@ static int tegra_adma_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_clk_destroy(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int tegra_adma_pm_suspend(struct device *dev)
{
return pm_runtime_suspended(dev) == false;
}
#endif
static const struct dev_pm_ops tegra_adma_dev_pm_ops = {
SET_RUNTIME_PM_OPS(tegra_adma_runtime_suspend,
tegra_adma_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(tegra_adma_pm_suspend, NULL)
SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static struct platform_driver tegra_admac_driver = {

View File

@ -703,7 +703,7 @@ static void xgene_dma_cleanup_descriptors(struct xgene_dma_chan *chan)
INIT_LIST_HEAD(&ld_completed);
spin_lock_bh(&chan->lock);
spin_lock(&chan->lock);
/* Clean already completed and acked descriptors */
xgene_dma_clean_completed_descriptor(chan);
@ -772,7 +772,7 @@ static void xgene_dma_cleanup_descriptors(struct xgene_dma_chan *chan)
*/
xgene_chan_xfer_ld_pending(chan);
spin_unlock_bh(&chan->lock);
spin_unlock(&chan->lock);
/* Run the callback for each descriptor, in order */
list_for_each_entry_safe(desc_sw, _desc_sw, &ld_completed, node) {
@ -797,7 +797,7 @@ static int xgene_dma_alloc_chan_resources(struct dma_chan *dchan)
return -ENOMEM;
}
chan_dbg(chan, "Allocate descripto pool\n");
chan_dbg(chan, "Allocate descriptor pool\n");
return 1;
}

View File

@ -28,6 +28,8 @@
#include <linux/seq_file.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/dma/idma64.h>
#include "intel-lpss.h"
#define LPSS_DEV_OFFSET 0x000
@ -96,8 +98,6 @@ static const struct resource intel_lpss_idma64_resources[] = {
DEFINE_RES_IRQ(0),
};
#define LPSS_IDMA64_DRIVER_NAME "idma64"
/*
* Cells needs to be ordered so that the iDMA is created first. This is
* because we need to be sure the DMA is available when the host controller

View File

@ -1498,12 +1498,7 @@ static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{
struct device *dev = param;
if (dev != chan->device->dev->parent)
return false;
return true;
return param == chan->device->dev;
}
#endif /* CONFIG_PCI */

View File

@ -365,7 +365,7 @@ static bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param)
static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
{
return param == chan->device->dev->parent;
return param == chan->device->dev;
}
/*
@ -434,7 +434,7 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
data->uart_16550_compatible = true;
}
/* Platforms with iDMA */
/* Platforms with iDMA 64-bit */
if (platform_get_resource_byname(to_platform_device(p->dev),
IORESOURCE_MEM, "lpss_priv")) {
data->dma.rx_param = p->dev->parent;

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Definitions for the Intel integrated DMA 64-bit
*
* Copyright (C) 2019 Intel Corporation
*/
#ifndef __LINUX_DMA_IDMA64_H__
#define __LINUX_DMA_IDMA64_H__
/* Platform driver name */
#define LPSS_IDMA64_DRIVER_NAME "idma64"
#endif /* __LINUX_DMA_IDMA64_H__ */