From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 03 Jan 2024 09:43:39 +0000
Subject: [PATCH] update kernel to 5.10.198

---
 kernel/drivers/dma/pl330.c |  203 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 133 insertions(+), 70 deletions(-)

diff --git a/kernel/drivers/dma/pl330.c b/kernel/drivers/dma/pl330.c
index b1d6fae..0d14147 100644
--- a/kernel/drivers/dma/pl330.c
+++ b/kernel/drivers/dma/pl330.c
@@ -405,6 +405,12 @@
 	 */
 	BUSY,
 	/*
+	 * Pause was called while descriptor was BUSY. Due to hardware
+	 * limitations, only termination is possible for descriptors
+	 * that have been paused.
+	 */
+	PAUSED,
+	/*
 	 * Sitting on the channel work_list but xfer done
 	 * by PL330 core
 	 */
@@ -541,11 +547,9 @@
 	/* For cyclic capability */
 	bool cyclic;
 	size_t num_periods;
-#ifdef CONFIG_NO_GKI
-	/* interlace size */
-	unsigned int src_interlace_size;
-	unsigned int dst_interlace_size;
-#endif
+
+	/* interleaved size */
+	struct data_chunk sgl;
 };
 
 struct _xfer_spec {
@@ -1073,7 +1077,7 @@
 	return true;
 }
 
-static bool _start(struct pl330_thread *thrd)
+static bool pl330_start_thread(struct pl330_thread *thrd)
 {
 	switch (_state(thrd)) {
 	case PL330_STATE_FAULT_COMPLETING:
@@ -1204,7 +1208,7 @@
 				 const struct _xfer_spec *pxs, int cyc,
 				 enum pl330_cond cond)
 {
-	int off = 0;
+	int off = 0, i = 0, burstn = 1;
 
 	/*
 	 * do FLUSHP at beginning to clear any stale dma requests before the
@@ -1212,30 +1216,36 @@
 	 */
 	if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
 		off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
+
+	if (pxs->desc->sgl.size) {
+		WARN_ON(BYTE_MOD_BURST_LEN(pxs->desc->sgl.size, pxs->ccr));
+		burstn = BYTE_TO_BURST(pxs->desc->sgl.size, pxs->ccr);
+	}
+
 	while (cyc--) {
-		off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
-		off += _emit_load(dry_run, &buf[off], cond, pxs->desc->rqtype,
-			pxs->desc->peri);
-		off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype,
-			pxs->desc->peri);
-#ifdef CONFIG_NO_GKI
+		for (i = 0; i < burstn; i++) {
+			off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
+			off += _emit_load(dry_run, &buf[off], cond, pxs->desc->rqtype,
+				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)
+			if (pxs->desc->sgl.dst_icg)
 				off += _emit_ADDH(dry_run, &buf[off], DST,
-						  pxs->desc->dst_interlace_size);
+						  pxs->desc->sgl.dst_icg);
 			break;
 		case DMA_MEM_TO_DEV:
-			if (pxs->desc->src_interlace_size)
+			if (pxs->desc->sgl.src_icg)
 				off += _emit_ADDH(dry_run, &buf[off], SRC,
-						  pxs->desc->src_interlace_size);
+						  pxs->desc->sgl.src_icg);
 			break;
 		default:
 			WARN_ON(1);
 			break;
 		}
-#endif
 	}
 
 	return off;
@@ -1450,9 +1460,7 @@
 		off += _emit_LPEND(dry_run, &buf[off], &lpend);
 	}
 
-#ifdef CONFIG_NO_GKI
-	if (!pxs->desc->src_interlace_size &&
-	    !pxs->desc->dst_interlace_size) {
+	if (!pxs->desc->sgl.src_icg && !pxs->desc->sgl.dst_icg) {
 		num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr);
 
 		if (num_dregs) {
@@ -1460,14 +1468,6 @@
 			off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
 		}
 	}
-#else
-	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);
-	}
-#endif
 
 	off += _emit_SEV(dry_run, &buf[off], ev);
 
@@ -1535,26 +1535,18 @@
 		BRST_SIZE(ccr);
 	int off = 0;
 
-#ifdef CONFIG_NO_GKI
-	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);
-#endif
+	if (pxs->desc->sgl.size)
+		bursts = x->bytes / pxs->desc->sgl.size;
+
 	while (bursts) {
 		c = bursts;
 		off += _loop(pl330, dry_run, &buf[off], &c, pxs);
 		bursts -= c;
 	}
-#ifdef CONFIG_NO_GKI
-	if (!pxs->desc->src_interlace_size &&
-	    !pxs->desc->dst_interlace_size)
+
+	if (!pxs->desc->sgl.src_icg && !pxs->desc->sgl.dst_icg)
 		off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
-#else
-	off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
-#endif
+
 	return off;
 }
 
@@ -1585,14 +1577,9 @@
 	unsigned long bursts = BYTE_TO_BURST(x->bytes, ccr);
 	int off = 0;
 
-#ifdef CONFIG_NO_GKI
-	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);
-#endif
+	if (pxs->desc->sgl.size)
+		bursts = x->bytes / pxs->desc->sgl.size;
+
 	/* Setup Loop(s) */
 	off += _loop_cyclic(pl330, dry_run, &buf[off], bursts, pxs, ev);
 
@@ -1907,7 +1894,7 @@
 					thrd->req[active].desc = NULL;
 					thrd->req_running = -1;
 					/* Get going again ASAP */
-					_start(thrd);
+					pl330_start_thread(thrd);
 				}
 
 				/* For now, just make a list of callbacks to be done */
@@ -2248,7 +2235,7 @@
 	list_for_each_entry(desc, &pch->work_list, node) {
 
 		/* If already submitted */
-		if (desc->status == BUSY)
+		if (desc->status == BUSY || desc->status == PAUSED)
 			continue;
 
 		ret = pl330_submit_req(pch->thread, desc);
@@ -2309,7 +2296,7 @@
 	} else {
 		/* Make sure the PL330 Channel thread is active */
 		spin_lock(&pch->thread->dmac->lock);
-		_start(pch->thread);
+		pl330_start_thread(pch->thread);
 		spin_unlock(&pch->thread->dmac->lock);
 	}
 
@@ -2454,10 +2441,6 @@
 			pch->fifo_addr = slave_config->dst_addr;
 		if (slave_config->dst_addr_width)
 			pch->burst_sz = __ffs(slave_config->dst_addr_width);
-#ifdef CONFIG_NO_GKI
-		if (slave_config->src_interlace_size)
-			pch->slave_config.src_interlace_size = slave_config->src_interlace_size;
-#endif
 		pch->burst_len = fixup_burst_len(slave_config->dst_maxburst,
 			pch->dmac->quirks);
 	} else if (direction == DMA_DEV_TO_MEM) {
@@ -2465,10 +2448,6 @@
 			pch->fifo_addr = slave_config->src_addr;
 		if (slave_config->src_addr_width)
 			pch->burst_sz = __ffs(slave_config->src_addr_width);
-#ifdef CONFIG_NO_GKI
-		if (slave_config->dst_interlace_size)
-			pch->slave_config.dst_interlace_size = slave_config->dst_interlace_size;
-#endif
 		pch->burst_len = fixup_burst_len(slave_config->src_maxburst,
 			pch->dmac->quirks);
 	}
@@ -2541,6 +2520,7 @@
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
 	struct pl330_dmac *pl330 = pch->dmac;
+	struct dma_pl330_desc *desc;
 	unsigned long flags;
 
 	pm_runtime_get_sync(pl330->ddma.dev);
@@ -2550,6 +2530,10 @@
 	_stop(pch->thread);
 	spin_unlock(&pl330->lock);
 
+	list_for_each_entry(desc, &pch->work_list, node) {
+		if (desc->status == BUSY)
+			desc->status = PAUSED;
+	}
 	spin_unlock_irqrestore(&pch->lock, flags);
 	pm_runtime_mark_last_busy(pl330->ddma.dev);
 	pm_runtime_put_autosuspend(pl330->ddma.dev);
@@ -2639,7 +2623,7 @@
 		else if (running && desc == running)
 			transferred =
 				pl330_get_current_xferred_count(pch, desc);
-		else if (desc->status == BUSY)
+		else if (desc->status == BUSY || desc->status == PAUSED)
 			/*
 			 * Busy but not running means either just enqueued,
 			 * or finished and not yet marked done
@@ -2655,6 +2639,9 @@
 			switch (desc->status) {
 			case DONE:
 				ret = DMA_COMPLETE;
+				break;
+			case PAUSED:
+				ret = DMA_PAUSED;
 				break;
 			case PREP:
 			case BUSY:
@@ -2821,6 +2808,10 @@
 	desc->cyclic = false;
 	desc->num_periods = 1;
 
+	desc->sgl.size = 0;
+	desc->sgl.src_icg = 0;
+	desc->sgl.dst_icg = 0;
+
 	dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
 
 	return desc;
@@ -2936,10 +2927,82 @@
 	desc->cyclic = true;
 	desc->num_periods = len / period_len;
 	desc->txd.flags = flags;
+
+	return &desc->txd;
+}
+
+static struct dma_async_tx_descriptor *pl330_prep_interleaved_dma(
+	struct dma_chan *chan, struct dma_interleaved_template *xt,
+	unsigned long flags)
+{
+	struct dma_pl330_desc *desc = NULL;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	dma_addr_t dst = 0, src = 0;
+	size_t size, src_icg, dst_icg, period_bytes, buffer_bytes, full_buffer_bytes;
+	size_t nump = 0, numf = 0;
+
+	if (!xt->numf || !xt->sgl[0].size || xt->frame_size != 1)
+		return NULL;
+
 #ifdef CONFIG_NO_GKI
-	desc->src_interlace_size = pch->slave_config.src_interlace_size;
-	desc->dst_interlace_size = pch->slave_config.dst_interlace_size;
+	nump = xt->nump;
 #endif
+	numf = xt->numf;
+	size = xt->sgl[0].size;
+	period_bytes = size * nump;
+	buffer_bytes = size * numf;
+
+	if (flags & DMA_PREP_REPEAT && (!nump || (numf % nump)))
+		return NULL;
+
+	src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]);
+	dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]);
+
+	pl330_config_write(chan, &pch->slave_config, xt->dir);
+
+	if (!pl330_prep_slave_fifo(pch, xt->dir))
+		return NULL;
+
+	desc = pl330_get_desc(pch);
+	if (!desc) {
+		dev_err(chan->device->dev, "Failed to get desc\n");
+		return NULL;
+	}
+
+	if (xt->dir == DMA_MEM_TO_DEV) {
+		desc->rqcfg.src_inc = 1;
+		desc->rqcfg.dst_inc = 0;
+		src = xt->src_start;
+		dst = pch->fifo_dma;
+		full_buffer_bytes = (size + src_icg) * numf;
+	} else {
+		desc->rqcfg.src_inc = 0;
+		desc->rqcfg.dst_inc = 1;
+		src = pch->fifo_dma;
+		dst = xt->dst_start;
+		full_buffer_bytes = (size + dst_icg) * numf;
+	}
+
+	desc->rqtype = xt->dir;
+	desc->rqcfg.brst_size = pch->burst_sz;
+	desc->rqcfg.brst_len = pch->burst_len;
+	desc->bytes_requested = full_buffer_bytes;
+	desc->sgl.size = size;
+	desc->sgl.src_icg = src_icg;
+	desc->sgl.dst_icg = dst_icg;
+	desc->txd.flags = flags;
+
+	if (flags & DMA_PREP_REPEAT) {
+		desc->cyclic = true;
+		desc->num_periods = numf / nump;
+		fill_px(&desc->px, dst, src, period_bytes);
+	} else {
+		fill_px(&desc->px, dst, src, buffer_bytes);
+	}
+
+	dev_dbg(chan->device->dev, "size: %zu, src_icg: %zu, dst_icg: %zu, nump: %zu, numf: %zu\n",
+		size, src_icg, dst_icg, nump, numf);
+
 	return &desc->txd;
 }
 
@@ -3072,10 +3135,6 @@
 		desc->rqcfg.brst_len = pch->burst_len;
 		desc->rqtype = direction;
 		desc->bytes_requested = sg_dma_len(sg);
-#ifdef CONFIG_NO_GKI
-		desc->src_interlace_size = pch->slave_config.src_interlace_size;
-		desc->dst_interlace_size = pch->slave_config.dst_interlace_size;
-#endif
 	}
 
 	/* Return the last desc in the chain */
@@ -3311,12 +3370,16 @@
 		dma_cap_set(DMA_SLAVE, pd->cap_mask);
 		dma_cap_set(DMA_CYCLIC, pd->cap_mask);
 		dma_cap_set(DMA_PRIVATE, pd->cap_mask);
+		dma_cap_set(DMA_INTERLEAVE, pd->cap_mask);
+		dma_cap_set(DMA_REPEAT, pd->cap_mask);
+		dma_cap_set(DMA_LOAD_EOT, pd->cap_mask);
 	}
 
 	pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
 	pd->device_free_chan_resources = pl330_free_chan_resources;
 	pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
 	pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
+	pd->device_prep_interleaved_dma = pl330_prep_interleaved_dma;
 	pd->device_tx_status = pl330_tx_status;
 	pd->device_prep_slave_sg = pl330_prep_slave_sg;
 	pd->device_config = pl330_config;

--
Gitblit v1.6.2