dmaengine: pl330: add support for interlace size config

Change-Id: Ia1008d689591f80ee2b3c08e1596b83ccd762f63
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Signed-off-by: Jason Zhu <jason.zhu@rock-chips.com>
This commit is contained in:
Jason Zhu
2022-07-08 16:16:07 +08:00
committed by Tao Huang
parent 6dc85ffccf
commit e59c625392
2 changed files with 69 additions and 5 deletions

View File

@ -460,6 +460,8 @@ struct dma_pl330_chan {
/* DMA-mapped view of the FIFO; may differ if an IOMMU is present */
dma_addr_t fifo_dma;
enum dma_data_direction dir;
unsigned int src_interlace_size;
unsigned int dst_interlace_size;
/* for runtime pm tracking */
bool active;
@ -552,6 +554,9 @@ struct dma_pl330_desc {
/* For cyclic capability */
bool cyclic;
size_t num_periods;
/* interlace size */
unsigned int src_interlace_size;
unsigned int dst_interlace_size;
};
struct _xfer_spec {
@ -580,6 +585,22 @@ static inline u32 get_revision(u32 periph_id)
return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
}
static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
enum pl330_dst da, u16 val)
{
if (dry_run)
return SZ_DMAADDH;
buf[0] = CMD_DMAADDH;
buf[0] |= (da << 1);
*((__le16 *)&buf[1]) = cpu_to_le16(val);
PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n",
da == 1 ? "DA" : "SA", val);
return SZ_DMAADDH;
}
static inline u32 _emit_END(unsigned dry_run, u8 buf[])
{
if (dry_run)
@ -1206,6 +1227,21 @@ static inline int _ldst_peripheral(struct pl330_dmac *pl330,
pxs->desc->peri);
off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype,
pxs->desc->peri);
switch (pxs->desc->rqtype) {
case DMA_DEV_TO_MEM:
if (pxs->desc->dst_interlace_size)
off += _emit_ADDH(dry_run, &buf[off], DST,
pxs->desc->dst_interlace_size);
break;
case DMA_MEM_TO_DEV:
if (pxs->desc->src_interlace_size)
off += _emit_ADDH(dry_run, &buf[off], SRC,
pxs->desc->src_interlace_size);
break;
default:
WARN_ON(1);
break;
}
}
return off;
@ -1421,11 +1457,14 @@ static int _period(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[],
off += _emit_LPEND(dry_run, &buf[off], &lpend);
}
num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr);
if (!pxs->desc->src_interlace_size &&
!pxs->desc->dst_interlace_size) {
num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr);
if (num_dregs) {
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
if (num_dregs) {
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
}
}
off += _emit_SEV(dry_run, &buf[off], ev);
@ -1494,12 +1533,20 @@ static inline int _setup_loops(struct pl330_dmac *pl330,
BRST_SIZE(ccr);
int off = 0;
if (pxs->desc->rqtype == DMA_DEV_TO_MEM)
bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) +
pxs->desc->dst_interlace_size);
else if (pxs->desc->rqtype == DMA_MEM_TO_DEV)
bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) +
pxs->desc->src_interlace_size);
while (bursts) {
c = bursts;
off += _loop(pl330, dry_run, &buf[off], &c, pxs);
bursts -= c;
}
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
if (!pxs->desc->src_interlace_size &&
!pxs->desc->dst_interlace_size)
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
return off;
}
@ -1531,6 +1578,12 @@ static inline int _setup_xfer_cyclic(struct pl330_dmac *pl330,
unsigned long bursts = BYTE_TO_BURST(x->bytes, ccr);
int off = 0;
if (pxs->desc->rqtype == DMA_DEV_TO_MEM)
bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr)
+ pxs->desc->dst_interlace_size);
else if (pxs->desc->rqtype == DMA_MEM_TO_DEV)
bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr)
+ pxs->desc->src_interlace_size);
/* Setup Loop(s) */
off += _loop_cyclic(pl330, dry_run, &buf[off], bursts, pxs, ev);
@ -2390,6 +2443,8 @@ static int pl330_config(struct dma_chan *chan,
pch->fifo_addr = slave_config->dst_addr;
if (slave_config->dst_addr_width)
pch->burst_sz = __ffs(slave_config->dst_addr_width);
if (slave_config->src_interlace_size)
pch->src_interlace_size = slave_config->src_interlace_size;
pch->burst_len = fixup_burst_len(slave_config->dst_maxburst,
pch->dmac->quirks);
} else if (slave_config->direction == DMA_DEV_TO_MEM) {
@ -2397,6 +2452,8 @@ static int pl330_config(struct dma_chan *chan,
pch->fifo_addr = slave_config->src_addr;
if (slave_config->src_addr_width)
pch->burst_sz = __ffs(slave_config->src_addr_width);
if (slave_config->dst_interlace_size)
pch->dst_interlace_size = slave_config->dst_interlace_size;
pch->burst_len = fixup_burst_len(slave_config->src_maxburst,
pch->dmac->quirks);
}
@ -2854,6 +2911,9 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
desc->num_periods = len / period_len;
desc->txd.flags = flags;
desc->src_interlace_size = pch->src_interlace_size;
desc->dst_interlace_size = pch->dst_interlace_size;
return &desc->txd;
}
@ -2984,6 +3044,8 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc->rqcfg.brst_len = pch->burst_len;
desc->rqtype = direction;
desc->bytes_requested = sg_dma_len(sg);
desc->src_interlace_size = pch->src_interlace_size;
desc->dst_interlace_size = pch->dst_interlace_size;
}
/* Return the last desc in the chain */

View File

@ -376,6 +376,8 @@ struct dma_slave_config {
u32 dst_port_window_size;
bool device_fc;
unsigned int slave_id;
unsigned int src_interlace_size;
unsigned int dst_interlace_size;
};
/**