All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joy Zou <joy.zou@nxp.com>
To: Frank Li <frank.li@nxp.com>,
	"vkoul@kernel.org" <vkoul@kernel.org>,
	"robh+dt@kernel.org" <robh+dt@kernel.org>,
	"krzysztof.kozlowski+dt@linaro.org"
	<krzysztof.kozlowski+dt@linaro.org>,
	"dmaengine@vger.kernel.org" <dmaengine@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Peng Fan <peng.fan@nxp.com>, Shenwei Wang <shenwei.wang@nxp.com>,
	"imx@lists.linux.dev" <imx@lists.linux.dev>
Cc: Peng Fan <peng.fan@nxp.com>, Aisheng Dong <aisheng.dong@nxp.com>
Subject: RE: [PATCH v3 11/12] dmaengine: fsl-edma: integrate v3 support
Date: Fri, 2 Jun 2023 09:41:19 +0000	[thread overview]
Message-ID: <AM6PR04MB59252F1C1BE15C61911C60EEE14EA@AM6PR04MB5925.eurprd04.prod.outlook.com> (raw)
In-Reply-To: <20230601144107.1636833-12-Frank.Li@nxp.com>


> -----Original Message-----
> From: Frank Li <frank.li@nxp.com>
> Sent: 2023年6月1日 22:41
> To: vkoul@kernel.org; robh+dt@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> dmaengine@vger.kernel.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org; Peng Fan <peng.fan@nxp.com>; Joy Zou
> <joy.zou@nxp.com>; Shenwei Wang <shenwei.wang@nxp.com>;
> imx@lists.linux.dev
> Subject: [PATCH v3 11/12] dmaengine: fsl-edma: integrate v3 support
> 
> Significant alterations have been made to the EDMA v3's register layout.
> Now, each channel possesses a separate address space, encapsulating all
> channel-related controls and statuses, including IRQs. There are changes in bit
> position definitions as well. However, the fundamental control flow remains
> analogous to the previous versions.
> 
> EDMA v3 was utilized in imx8qm, imx93, and will be in forthcoming chips.
> 
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
>  drivers/dma/fsl-edma-common.c | 158 +++++++++++++++++++---
> drivers/dma/fsl-edma-common.h |  75 ++++++++++
>  drivers/dma/fsl-edma-main.c   | 248
> ++++++++++++++++++++++++++++++++--
>  3 files changed, 456 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/dma/fsl-edma-common.c
> b/drivers/dma/fsl-edma-common.c index eead6a4765f7..dbfc9d80e2ed
> 100644
> --- a/drivers/dma/fsl-edma-common.c
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -7,6 +7,8 @@
>  #include <linux/module.h>
>  #include <linux/slab.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/pm_domain.h>
> 
>  #include "fsl-edma-common.h"
> 
> @@ -66,11 +68,47 @@ void fsl_edma_tx_chan_handler(struct fsl_edma_chan
> *fsl_chan)
>  	spin_unlock(&fsl_chan->vchan.lock);
>  }
> 
> +static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan) {
> +	u32 val, flags;
> +
> +	flags = fsl_edma_drvflags(fsl_chan);
> +	val = edma_readl_chreg(fsl_chan, ch_sbr);
> +	/* Remote/local swapped wrongly on iMX8 QM Audio edma */
> +	if (flags & FSL_EDMA_DRV_QUIRK_SWAPPED) {
> +		if (!fsl_chan->is_rxchan)
> +			val |= EDMA_V3_CH_SBR_RD;
> +		else
> +			val |= EDMA_V3_CH_SBR_WR;
> +	} else {
> +		if (fsl_chan->is_rxchan)
> +			val |= EDMA_V3_CH_SBR_RD;
> +		else
> +			val |= EDMA_V3_CH_SBR_WR;
> +	}
> +
> +	if (fsl_chan->is_remote)
> +		val &= ~(EDMA_V3_CH_SBR_RD | EDMA_V3_CH_SBR_WR);
> +
> +	edma_writel_chreg(fsl_chan, val, ch_sbr);
> +
> +	if ((flags & (FSL_EDMA_DRV_AXI | FSL_EDMA_DRV_HAS_CHMUX)) &&
> +	    fsl_chan->srcid && !edma_readl_chreg(fsl_chan, ch_mux))
> +		edma_writel_chreg(fsl_chan, fsl_chan->srcid, ch_mux);
> +
> +	val = edma_readl_chreg(fsl_chan, ch_csr);
> +	val |= EDMA_V3_CH_CSR_ERQ;
> +	edma_writel_chreg(fsl_chan, val, ch_csr); }
> +
>  static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)  {
>  	struct edma_regs *regs = &fsl_chan->edma->regs;
>  	u32 ch = fsl_chan->vchan.chan.chan_id;
> 
> +	if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_SPLIT_REG)
> +		return fsl_edma3_enable_request(fsl_chan);
> +
>  	if (fsl_chan->edma->drvdata->flags & FSL_EDMA_DRV_WRAP_IO) {
>  		edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
>  		edma_writeb(fsl_chan->edma, ch, regs->serq); @@ -83,11 +121,29
> @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
>  	}
>  }
> 
> +static void fsl_edma3_disable_request(struct fsl_edma_chan *fsl_chan) {
> +	u32 val = edma_readl_chreg(fsl_chan, ch_csr);
> +	u32 flags;
> +
> +	flags = fsl_edma_drvflags(fsl_chan);
> +
> +	if ((flags & (FSL_EDMA_DRV_AXI | FSL_EDMA_DRV_HAS_CHMUX)) &&
> +	    fsl_chan->srcid)
> +		edma_writel_chreg(fsl_chan, 0, ch_mux);
> +
> +	val &= ~EDMA_V3_CH_CSR_ERQ;
> +	edma_writel_chreg(fsl_chan, val, ch_csr); }
> +
>  void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)  {
>  	struct edma_regs *regs = &fsl_chan->edma->regs;
>  	u32 ch = fsl_chan->vchan.chan.chan_id;
> 
> +	if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_SPLIT_REG)
> +		return fsl_edma3_disable_request(fsl_chan);
> +
>  	if (fsl_chan->edma->drvdata->flags & FSL_EDMA_DRV_WRAP_IO) {
>  		edma_writeb(fsl_chan->edma, ch, regs->cerq);
>  		edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
> @@ -186,6 +242,10 @@ int fsl_edma_terminate_all(struct dma_chan *chan)
>  	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
>  	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
>  	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> +
> +	if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_PD)
> +		pm_runtime_allow(fsl_chan->pd_dev);
> +
>  	return 0;
>  }
> 
> @@ -286,12 +346,16 @@ static size_t fsl_edma_desc_residue(struct
> fsl_edma_chan *fsl_chan,
>  	enum dma_transfer_direction dir = edesc->dirn;
>  	dma_addr_t cur_addr, dma_addr;
>  	size_t len, size;
> +	u32 nbytes = 0;
>  	int i;
> 
>  	/* calculate the total size in this desc */
> -	for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
> -		len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
> -			* le16_to_cpu(edesc->tcd[i].vtcd->biter);
> +	for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++) {
> +		nbytes = le32_to_cpu(edesc->tcd[i].vtcd->nbytes);
> +		if (nbytes & (EDMA_V3_TCD_NBYTES_DMLOE |
> EDMA_V3_TCD_NBYTES_SMLOE))
> +			nbytes = EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(nbytes);
> +		len += nbytes * le16_to_cpu(edesc->tcd[i].vtcd->biter);
> +	}
> 
>  	if (!in_progress)
>  		return len;
> @@ -303,8 +367,12 @@ static size_t fsl_edma_desc_residue(struct
> fsl_edma_chan *fsl_chan,
> 
>  	/* figure out the finished and calculate the residue */
>  	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
> -		size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
> -			* le16_to_cpu(edesc->tcd[i].vtcd->biter);
> +		nbytes = le32_to_cpu(edesc->tcd[i].vtcd->nbytes);
> +		if (nbytes & (EDMA_V3_TCD_NBYTES_DMLOE |
> EDMA_V3_TCD_NBYTES_SMLOE))
> +			nbytes = EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(nbytes);
> +
> +		size = nbytes * le16_to_cpu(edesc->tcd[i].vtcd->biter);
> +
>  		if (dir == DMA_MEM_TO_DEV)
>  			dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
>  		else
> @@ -389,13 +457,15 @@ static void fsl_edma_set_tcd_regs(struct
> fsl_edma_chan *fsl_chan,  }
> 
>  static inline
> -void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
> +void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
> +		       struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
>  		       u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
>  		       u16 biter, u16 doff, u32 dlast_sga, bool major_int,
>  		       bool disable_req, bool enable_sg)  {
> +	struct dma_slave_config *cfg = &fsl_chan->cfg;
>  	u16 csr = 0;
> -
> +	u32 burst;
>  	/*
>  	 * eDMA hardware SGs require the TCDs to be stored in little
>  	 * endian format irrespective of the register endian model.
> @@ -409,6 +479,21 @@ void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd,
> u32 src, u32 dst,
> 
>  	tcd->soff = cpu_to_le16(soff);
> 
> +	if (fsl_chan->is_multi_fifo) {
> +		/* set mloff to support multiple fifo */
> +		burst = cfg->direction == DMA_DEV_TO_MEM ?
> +				cfg->src_addr_width : cfg->dst_addr_width;
> +		nbytes |= EDMA_V3_TCD_NBYTES_MLOFF(-(burst * 4));
> +		/* enable DMLOE/SMLOE */
> +		if (cfg->direction == DMA_MEM_TO_DEV) {
> +			nbytes |= EDMA_V3_TCD_NBYTES_DMLOE;
> +			nbytes &= ~EDMA_V3_TCD_NBYTES_SMLOE;
> +		} else {
> +			nbytes |= EDMA_V3_TCD_NBYTES_SMLOE;
> +			nbytes &= ~EDMA_V3_TCD_NBYTES_DMLOE;
> +		}
> +	}
> +
>  	tcd->nbytes = cpu_to_le32(nbytes);
>  	tcd->slast = cpu_to_le32(slast);
> 
> @@ -427,6 +512,12 @@ void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd,
> u32 src, u32 dst,
>  	if (enable_sg)
>  		csr |= EDMA_TCD_CSR_E_SG;
> 
> +	if (fsl_chan->is_rxchan)
> +		csr |= EDMA_TCD_CSR_ACTIVE;
> +
> +	if (fsl_chan->is_sw)
> +		csr |= EDMA_TCD_CSR_START;
> +
>  	tcd->csr = cpu_to_le16(csr);
>  }
> 
> @@ -466,6 +557,7 @@ struct dma_async_tx_descriptor
> *fsl_edma_prep_dma_cyclic(
>  	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
>  	struct fsl_edma_desc *fsl_desc;
>  	dma_addr_t dma_buf_next;
> +	bool major_int = true;
>  	int sg_len, i;
>  	u32 src_addr, dst_addr, last_sg, nbytes;
>  	u16 soff, doff, iter;
> @@ -509,17 +601,23 @@ struct dma_async_tx_descriptor
> *fsl_edma_prep_dma_cyclic(
>  			src_addr = dma_buf_next;
>  			dst_addr = fsl_chan->dma_dev_addr;
>  			soff = fsl_chan->cfg.dst_addr_width;
> -			doff = 0;
> -		} else {
> +			doff = fsl_chan->is_multi_fifo ? 4 : 0;
> +		} else if (direction == DMA_DEV_TO_MEM) {
>  			src_addr = fsl_chan->dma_dev_addr;
>  			dst_addr = dma_buf_next;
> -			soff = 0;
> +			soff = fsl_chan->is_multi_fifo ? 4 : 0;
>  			doff = fsl_chan->cfg.src_addr_width;
> +		} else {
> +			/* DMA_DEV_TO_DEV */
> +			src_addr = fsl_chan->cfg.src_addr;
> +			dst_addr = fsl_chan->cfg.dst_addr;
> +			soff = doff = 0;
> +			major_int = false;
>  		}
> 
> -		fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
> +		fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
> +dst_addr,
>  				  fsl_chan->attr, soff, nbytes, 0, iter,
> -				  iter, doff, last_sg, true, false, true);
> +				  iter, doff, last_sg, major_int, false, true);
>  		dma_buf_next += period_len;
>  	}
> 
> @@ -568,23 +666,51 @@ struct dma_async_tx_descriptor
> *fsl_edma_prep_slave_sg(
>  			dst_addr = fsl_chan->dma_dev_addr;
>  			soff = fsl_chan->cfg.dst_addr_width;
>  			doff = 0;
> -		} else {
> +		} else if (direction == DMA_DEV_TO_MEM) {
>  			src_addr = fsl_chan->dma_dev_addr;
>  			dst_addr = sg_dma_address(sg);
>  			soff = 0;
>  			doff = fsl_chan->cfg.src_addr_width;
> +		} else {
> +			/* DMA_DEV_TO_DEV */
> +			src_addr = fsl_chan->cfg.src_addr;
> +			dst_addr = fsl_chan->cfg.dst_addr;
> +			soff = 0;
> +			doff = 0;
>  		}
> 
> +		/*
> +		 * Choose the suitable burst length if sg_dma_len is not
> +		 * multiple of burst length so that the whole transfer length is
> +		 * multiple of minor loop(burst length).
> +		 */
> +		if (sg_dma_len(sg) % nbytes) {
> +			u32 width = (direction == DMA_DEV_TO_MEM) ? doff : soff;
> +			u32 burst = (direction == DMA_DEV_TO_MEM) ?
> +						fsl_chan->cfg.src_maxburst :
> +						fsl_chan->cfg.dst_maxburst;
> +			int j;
> +
> +			for (j = burst; j > 1; j--) {
> +				if (!(sg_dma_len(sg) % (j * width))) {
> +					nbytes = j * width;
> +					break;
> +				}
> +			}
> +			/* Set burst size as 1 if there's no suitable one */
> +			if (j == 1)
> +				nbytes = width;
> +		}
>  		iter = sg_dma_len(sg) / nbytes;
>  		if (i < sg_len - 1) {
>  			last_sg = fsl_desc->tcd[(i + 1)].ptcd;
> -			fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
> +			fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
>  					  dst_addr, fsl_chan->attr, soff,
>  					  nbytes, 0, iter, iter, doff, last_sg,
>  					  false, false, true);
>  		} else {
>  			last_sg = 0;
> -			fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
> +			fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
>  					  dst_addr, fsl_chan->attr, soff,
>  					  nbytes, 0, iter, iter, doff, last_sg,
>  					  true, true, false);
> @@ -609,7 +735,7 @@ struct dma_async_tx_descriptor
> *fsl_edma_prep_memcpy(struct dma_chan *chan,
>  	fsl_chan->is_sw = true;
> 
>  	/* To match with copy_align and max_seg_size so 1 tcd is enough */
> -	fsl_edma_fill_tcd(fsl_desc->tcd[0].vtcd, dma_src, dma_dst,
> +	fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[0].vtcd, dma_src, dma_dst,
>  			fsl_edma_get_tcd_attr(DMA_SLAVE_BUSWIDTH_32_BYTES),
>  			32, len, 0, 1, 1, 32, 0, true, true, false);
> 
> diff --git a/drivers/dma/fsl-edma-common.h
> b/drivers/dma/fsl-edma-common.h index cfc41915eaa1..d4ac2644654e
> 100644
> --- a/drivers/dma/fsl-edma-common.h
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -42,6 +42,11 @@
>  #define EDMA_TCD_CSR_ACTIVE		BIT(6)
>  #define EDMA_TCD_CSR_DONE		BIT(7)
> 
> +#define EDMA_V3_TCD_NBYTES_MLOFF_NBYTES(x) ((x) & GENMASK(9, 0))
> +#define EDMA_V3_TCD_NBYTES_MLOFF(x)        (x << 10)
> +#define EDMA_V3_TCD_NBYTES_DMLOE           (1 << 30)
> +#define EDMA_V3_TCD_NBYTES_SMLOE           (1 << 31)
> +
>  #define EDMAMUX_CHCFG_DIS		0x0
>  #define EDMAMUX_CHCFG_ENBL		0x80
>  #define EDMAMUX_CHCFG_SOURCE(n)		((n) & 0x3F)
> @@ -54,6 +59,15 @@
>  				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
>  				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
>  				 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
> +
> +#define EDMA_V3_CH_SBR_RD          BIT(22)
> +#define EDMA_V3_CH_SBR_WR          BIT(21)
> +#define EDMA_V3_CH_CSR_ERQ         BIT(0)
> +#define EDMA_V3_CH_CSR_EARQ        BIT(1)
> +#define EDMA_V3_CH_CSR_EEI         BIT(2)
> +#define EDMA_V3_CH_CSR_DONE        BIT(30)
> +#define EDMA_V3_CH_CSR_ACTIVE      BIT(31)
> +
>  enum fsl_edma_pm_state {
>  	RUNNING = 0,
>  	SUSPENDED,
> @@ -73,6 +87,18 @@ struct fsl_edma_hw_tcd {
>  	__le16	biter;
>  };
> 
> +struct fsl_edma3_ch_reg {
> +	__le32	ch_csr;
> +	__le32	ch_es;
> +	__le32	ch_int;
> +	__le32	ch_sbr;
> +	__le32	ch_pri;
> +	__le32	ch_mux;
> +	__le32  ch_mattr; /* edma4, reserved for edma3 */
> +	__le32  ch_reserved;
> +	struct fsl_edma_hw_tcd tcd;
> +} __packed;
> +
>  /*
>   * These are iomem pointers, for both v32 and v64.
>   */
> @@ -119,6 +145,18 @@ struct fsl_edma_chan {
>  	enum dma_data_direction		dma_dir;
>  	char				chan_name[32];
>  	struct fsl_edma_hw_tcd __iomem *tcd;
> +	u32				real_count;
> +	struct work_struct		issue_worker;
> +	struct platform_device		*pdev;
> +	struct device			*pd_dev;
> +	u32				srcid;
> +	struct clk			*clk;
> +	int                             priority;
> +	int				hw_chanid;
> +	int				txirq;
> +	bool				is_rxchan;
> +	bool				is_remote;
> +	bool				is_multi_fifo;
>  };
> 
>  struct fsl_edma_desc {
> @@ -135,8 +173,30 @@ struct fsl_edma_desc {
>  #define FSL_EDMA_DRV_CONFIG32		BIT(2)
>  #define FSL_EDMA_DRV_WRAP_IO		BIT(3)
>  #define FSL_EDMA_DRV_EDMA64		BIT(4)
> +#define FSL_EDMA_DRV_HAS_PD		BIT(5)
> +#define FSL_EDMA_DRV_HAS_CHCLK		BIT(6)
> +#define FSL_EDMA_DRV_HAS_CHMUX		BIT(7)
> +/* imx8 QM audio edma remote local swapped */
> +#define FSL_EDMA_DRV_QUIRK_SWAPPED	BIT(8)
> +/* imx93 edma4 is AXI master */
> +#define FSL_EDMA_DRV_AXI		BIT(9)
> +/* control and status register is in tcd address space, edma3 reg layout */
> +#define FSL_EDMA_DRV_SPLIT_REG		BIT(10)
> +#define FSL_EDMA_DRV_BUS_8BYTE		BIT(11)
> +#define FSL_EDMA_DRV_DEV_TO_DEV		BIT(12)
> +#define FSL_EDMA_DRV_ALIGN_64BYTE	BIT(13)
> +
> +#define FSL_EDMA_DRV_EDMA3	(FSL_EDMA_DRV_SPLIT_REG |	\
> +				 FSL_EDMA_DRV_BUS_8BYTE |	\
> +				 FSL_EDMA_DRV_DEV_TO_DEV |	\
> +				 FSL_EDMA_DRV_ALIGN_64BYTE)
> +
> +#define FSL_EDMA_DRV_EDMA4	(FSL_EDMA_DRV_EDMA3 |		\
> +				 FSL_EDMA_DRV_AXI)
>  struct fsl_edma_drvdata {
>  	u32			dmamuxs;
> +	u32			chreg_off;
> +	u32			chreg_space_sz;
>  	u32			flags;
>  	int			(*setup_irq)(struct platform_device *pdev,
>  					     struct fsl_edma_engine *fsl_edma); @@ -148,6
> +208,7 @@ struct fsl_edma_engine {
>  	void __iomem		*muxbase[DMAMUX_NR];
>  	struct clk		*muxclk[DMAMUX_NR];
>  	struct clk		*dmaclk;
> +	struct clk		*chclk;
>  	struct mutex		fsl_edma_mutex;
>  	const struct fsl_edma_drvdata *drvdata;
>  	u32			n_chans;
> @@ -155,6 +216,7 @@ struct fsl_edma_engine {
>  	int			errirq;
>  	bool			big_endian;
>  	struct edma_regs	regs;
> +	u64			chan_masked;
>  	struct fsl_edma_chan	chans[];
>  };
> 
> @@ -168,6 +230,14 @@ struct fsl_edma_engine {
>  	edma_writel(chan->edma, (u32 __force)val, &chan->tcd->__name) :	\
>  	edma_writew(chan->edma, (u16 __force)val, &chan->tcd->__name))
> 
> +#define edma_readl_chreg(chan, __name)				\
> +	edma_readl(chan->edma,					\
> +		   (void __iomem *)&(container_of(chan->tcd, struct
> fsl_edma3_ch_reg,
> +tcd)->__name))
> +
> +#define edma_writel_chreg(chan, val,  __name)			\
> +	edma_writel(chan->edma, val,				\
> +		   (void __iomem *)&(container_of(chan->tcd, struct
> fsl_edma3_ch_reg,
> +tcd)->__name))
> +
>  /*
>   * R/W functions for big- or little-endian registers:
>   * The eDMA controller's endian is independent of the CPU core's endian.
> @@ -224,6 +294,11 @@ static inline struct fsl_edma_chan
> *to_fsl_edma_chan(struct dma_chan *chan)
>  	return container_of(chan, struct fsl_edma_chan, vchan.chan);  }
> 
> +static inline u32 fsl_edma_drvflags(struct fsl_edma_chan *fsl_chan) {
> +	return fsl_chan->edma->drvdata->flags; }
> +
>  static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc
> *vd)  {
>  	return container_of(vd, struct fsl_edma_desc, vdesc); diff --git
> a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index
> e5f42dd974e8..33339ade79a4 100644
> --- a/drivers/dma/fsl-edma-main.c
> +++ b/drivers/dma/fsl-edma-main.c
> @@ -18,9 +18,15 @@
>  #include <linux/of_irq.h>
>  #include <linux/of_dma.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/pm_domain.h>
> 
>  #include "fsl-edma-common.h"
> 
> +#define ARGS_RX                         BIT(0)
> +#define ARGS_REMOTE                     BIT(1)
> +#define ARGS_MULTI_FIFO                 BIT(2)
> +
>  static void fsl_edma_synchronize(struct dma_chan *chan)  {
>  	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); @@ -47,6
> +53,22 @@ static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
> 
> +static irqreturn_t fsl_edma3_tx_handler(int irq, void *dev_id) {
> +	struct fsl_edma_chan *fsl_chan = dev_id;
> +	unsigned int intr;
> +
> +	intr = edma_readl_chreg(fsl_chan, ch_int);
> +	if (!intr)
> +		return IRQ_HANDLED;
> +
> +	edma_writel_chreg(fsl_chan, 1, ch_int);
> +
> +	fsl_edma_tx_chan_handler(fsl_chan);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)  {
>  	struct fsl_edma_engine *fsl_edma = dev_id; @@ -108,6 +130,52 @@
> static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
>  	return NULL;
>  }
> 
> +static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
> +					struct of_dma *ofdma)
> +{
> +	struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
> +	struct dma_chan *chan, *_chan;
> +	struct fsl_edma_chan *fsl_chan;
> +	int i;
> +
> +	if (dma_spec->args_count != 3)
> +		return NULL;
> +
> +	mutex_lock(&fsl_edma->fsl_edma_mutex);
> +	list_for_each_entry_safe(chan, _chan, &fsl_edma->dma_dev.channels,
> +					device_node) {
> +
> +		if (chan->client_count)
> +			continue;
> +
> +		fsl_chan = to_fsl_edma_chan(chan);
> +		i = fsl_chan - fsl_edma->chans;
> +		if (fsl_edma->drvdata->dmamuxs == 0 && i == dma_spec->args[0]) {
> +			chan = dma_get_slave_channel(chan);
> +			chan->device->privatecnt++;
> +			fsl_chan->priority = dma_spec->args[1];
> +			fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
> +			fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
> +			fsl_chan->is_multi_fifo = dma_spec->args[2] &
> ARGS_MULTI_FIFO;
> +			mutex_unlock(&fsl_edma->fsl_edma_mutex);
> +			return chan;
> +		} else if ((fsl_edma->drvdata->dmamuxs ||
> +			   (fsl_edma->drvdata->flags & FSL_EDMA_DRV_AXI))
> && !fsl_chan->srcid) {
> +			chan = dma_get_slave_channel(chan);
> +			chan->device->privatecnt++;
> +			fsl_chan->priority = dma_spec->args[1];
> +			fsl_chan->srcid = dma_spec->args[0];
> +			fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
> +			fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
> +			fsl_chan->is_multi_fifo = dma_spec->args[2] &
> ARGS_MULTI_FIFO;
> +			mutex_unlock(&fsl_edma->fsl_edma_mutex);
> +			return chan;
> +		}
> +	}
> +	mutex_unlock(&fsl_edma->fsl_edma_mutex);
> +	return NULL;
> +}
> +
>  static int
>  fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine
> *fsl_edma)  { @@ -149,6 +217,37 @@ fsl_edma_irq_init(struct
> platform_device *pdev, struct fsl_edma_engine *fsl_edma
>  	return 0;
>  }
> 
> +static int fsl_edma3_irq_init(struct platform_device *pdev, struct
> +fsl_edma_engine *fsl_edma) {
> +	int ret;
> +	int i;
> +
> +	for (i = 0; i < fsl_edma->n_chans; i++) {
> +
> +		struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i];
> +
> +		if (fsl_edma->chan_masked & BIT(i))
> +			continue;
> +
> +		/* request channel irq */
> +		fsl_chan->txirq = platform_get_irq(pdev, i);
> +		if (fsl_chan->txirq < 0) {
> +			dev_err(&pdev->dev, "Can't get chan %d's irq.\n", i);
> +			return  -EINVAL;
> +		}
> +
> +		ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
> +			fsl_edma3_tx_handler, IRQF_SHARED,
> +			fsl_chan->chan_name, fsl_chan);
> +		if (ret) {
> +			dev_err(&pdev->dev, "Can't register chan%d's IRQ.\n", i);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int
>  fsl_edma2_irq_init(struct platform_device *pdev,
>  		   struct fsl_edma_engine *fsl_edma)
> @@ -202,29 +301,115 @@ static void fsl_disable_clocks(struct
> fsl_edma_engine *fsl_edma, int nr_clocks)
> 
>  static struct fsl_edma_drvdata vf610_data = {
>  	.dmamuxs = DMAMUX_NR | FSL_EDMA_DRV_WRAP_IO,
> +	.dmamuxs = DMAMUX_NR,
> +	.chreg_off = EDMA_TCD,
> +	.chreg_space_sz = sizeof(struct fsl_edma_hw_tcd),
>  	.setup_irq = fsl_edma_irq_init,
>  };
> 
>  static struct fsl_edma_drvdata ls1028a_data = {
>  	.dmamuxs = DMAMUX_NR,
>  	.flags = FSL_EDMA_DRV_MUX_SWAP | FSL_EDMA_DRV_WRAP_IO,
> +	.chreg_off = EDMA_TCD,
> +	.chreg_space_sz = sizeof(struct fsl_edma_hw_tcd),
>  	.setup_irq = fsl_edma_irq_init,
>  };
> 
>  static struct fsl_edma_drvdata imx7ulp_data = {
>  	.dmamuxs = 1,
> +	.chreg_off = EDMA_TCD,
> +	.chreg_space_sz = sizeof(struct fsl_edma_hw_tcd),
>  	.flags = FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_CONFIG32,
>  	.setup_irq = fsl_edma2_irq_init,
>  };
> 
> +static struct fsl_edma_drvdata imx8qm_data = {
> +	.flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_PD
> +		 | FSL_EDMA_DRV_EDMA3,
> +	.chreg_space_sz = 0x10000,
> +	.chreg_off = 0x10000,
> +	.setup_irq = fsl_edma3_irq_init,
> +};
Hi frank,
There are many dma controllers in imx8qm. But not all dma controllers support ch-mux.
In addition, Imx93 edma v3 also doesn't support ch-mux.
You can confirm with RM. Can we use the dts node property instead of drvdata flags? 
BR
Joy Zou
> +
> +static struct fsl_edma_drvdata imx8qm_audio_data = {
> +	.flags = FSL_EDMA_DRV_HAS_CHMUX |
> FSL_EDMA_DRV_QUIRK_SWAPPED |
> +		 FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3,
> +	.chreg_space_sz = 0x10000,
> +	.chreg_off = 0x10000,
> +	.setup_irq = fsl_edma3_irq_init,
> +};
> +
> +static struct fsl_edma_drvdata imx93_data3 = {
> +	.flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK
> +		 | FSL_EDMA_DRV_EDMA3,
> +	.chreg_space_sz = 0x10000,
> +	.chreg_off = 0x10000,
> +	.setup_irq = fsl_edma3_irq_init,
> +};
> +
> +static struct fsl_edma_drvdata imx93_data4 = {
> +	.flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK
> +		 | FSL_EDMA_DRV_EDMA4,
> +	.chreg_space_sz = 0x8000,
> +	.chreg_off = 0x10000,
> +	.setup_irq = fsl_edma3_irq_init,
> +};
> +
>  static const struct of_device_id fsl_edma_dt_ids[] = {
>  	{ .compatible = "fsl,vf610-edma", .data = &vf610_data},
>  	{ .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data},
>  	{ .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data},
> +	{ .compatible = "fsl,imx8qm-edma", .data = &imx8qm_data},
> +	{ .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data},
> +	{ .compatible = "fsl,imx93-edma3", .data = &imx93_data3},
> +	{ .compatible = "fsl,imx93-edma4", .data = &imx93_data4},
>  	{ /* sentinel */ }
>  };
> +
>  MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
> 
> +static int fsl_edma3_attach_pd(struct platform_device *pdev, struct
> +fsl_edma_engine *fsl_edma) {
> +	struct fsl_edma_chan *fsl_chan;
> +	struct device_link *link;
> +	struct device *pd_chan;
> +	struct device *dev;
> +	int i;
> +
> +	dev = &pdev->dev;
> +
> +	for (i = 0; i < fsl_edma->n_chans; i++) {
> +		if (fsl_edma->chan_masked & BIT(i))
> +			continue;
> +
> +		fsl_chan = &fsl_edma->chans[i];
> +
> +		pd_chan = dev_pm_domain_attach_by_id(dev, i);
> +		if (IS_ERR_OR_NULL(pd_chan)) {
> +			dev_err(dev, "Failed attach pd %d\n", i);
> +			return -EINVAL;
> +		}
> +
> +		link = device_link_add(dev, pd_chan, DL_FLAG_STATELESS |
> +					     DL_FLAG_PM_RUNTIME |
> +					     DL_FLAG_RPM_ACTIVE);
> +		if (IS_ERR(link)) {
> +			dev_err(dev, "Failed to add device_link to %d: %ld\n", i,
> +				PTR_ERR(link));
> +			return -EINVAL;
> +		}
> +
> +		fsl_chan->pd_dev = pd_chan;
> +
> +		pm_runtime_use_autosuspend(fsl_chan->pd_dev);
> +		pm_runtime_set_autosuspend_delay(fsl_chan->pd_dev, 200);
> +		pm_runtime_set_active(fsl_chan->pd_dev);
> +		//pm_runtime_put_sync_suspend(fsl_chan->pd_dev);
> +	}
> +
> +	return 0;
> +}
> +
>  static int fsl_edma_probe(struct platform_device *pdev)  {
>  	const struct of_device_id *of_id =
> @@ -263,8 +448,10 @@ static int fsl_edma_probe(struct platform_device
> *pdev)
>  	if (IS_ERR(fsl_edma->membase))
>  		return PTR_ERR(fsl_edma->membase);
> 
> -	fsl_edma_setup_regs(fsl_edma);
> -	regs = &fsl_edma->regs;
> +	if (!(drvdata->flags & FSL_EDMA_DRV_SPLIT_REG)) {
> +		fsl_edma_setup_regs(fsl_edma);
> +		regs = &fsl_edma->regs;
> +	}
> 
>  	if (drvdata->flags & FSL_EDMA_DRV_HAS_DMACLK) {
>  		fsl_edma->dmaclk = devm_clk_get_enabled(&pdev->dev, "dma");
> @@ -274,6 +461,17 @@ static int fsl_edma_probe(struct platform_device
> *pdev)
>  		}
>  	}
> 
> +	if (drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) {
> +		fsl_edma->chclk = devm_clk_get_enabled(&pdev->dev, "mp");
> +		if (IS_ERR(fsl_edma->chclk)) {
> +			dev_err(&pdev->dev, "Missing MP block clock.\n");
> +			return PTR_ERR(fsl_edma->chclk);
> +		}
> +	}
> +
> +	if (of_property_read_u64(np, "fsl,channel-mask",
> &fsl_edma->chan_masked))
> +		fsl_edma->chan_masked = 0;
> +
>  	for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) {
>  		char clkname[32];
> 
> @@ -296,9 +494,18 @@ static int fsl_edma_probe(struct platform_device
> *pdev)
> 
>  	fsl_edma->big_endian = of_property_read_bool(np, "big-endian");
> 
> +	if (drvdata->flags & FSL_EDMA_DRV_HAS_PD) {
> +		ret = fsl_edma3_attach_pd(pdev, fsl_edma);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	INIT_LIST_HEAD(&fsl_edma->dma_dev.channels);
>  	for (i = 0; i < fsl_edma->n_chans; i++) {
> -		struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i];
> +		fsl_chan = &fsl_edma->chans[i];
> +
> +		if (fsl_edma->chan_masked & BIT(i))
> +			continue;
> 
>  		snprintf(fsl_chan->chan_name, sizeof(fsl_chan->chan_name),
> "%s-CH%02d",
>  							   dev_name(&pdev->dev), i);
> @@ -309,12 +516,19 @@ static int fsl_edma_probe(struct platform_device
> *pdev)
>  		fsl_chan->idle = true;
>  		fsl_chan->dma_dir = DMA_NONE;
>  		fsl_chan->vchan.desc_free = fsl_edma_free_desc;
> -		fsl_chan->tcd = fsl_edma->membase + EDMA_TCD
> -				+ i * sizeof(struct fsl_edma_hw_tcd);
> +
> +		len = (drvdata->flags & FSL_EDMA_DRV_SPLIT_REG) ?
> +				offsetof(struct fsl_edma3_ch_reg, tcd) : 0;
> +		fsl_chan->tcd = fsl_edma->membase
> +				+ i * drvdata->chreg_space_sz + drvdata->chreg_off + len;
> +
> +		fsl_chan->pdev = pdev;
>  		vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
> 
>  		edma_write_tcdreg(fsl_chan, 0, csr);
> -		fsl_edma_chan_mux(fsl_chan, 0, false);
> +
> +		if (drvdata->dmamuxs)
> +			fsl_edma_chan_mux(fsl_chan, 0, false);
>  	}
> 
>  	ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma); @@ -344,12
> +558,25 @@ static int fsl_edma_probe(struct platform_device *pdev)
> 
>  	fsl_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
>  	fsl_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
> +
> +	if (drvdata->flags & FSL_EDMA_DRV_BUS_8BYTE) {
> +		fsl_edma->dma_dev.src_addr_widths |=
> BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
> +		fsl_edma->dma_dev.dst_addr_widths |=
> BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
> +	}
> +
>  	fsl_edma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) |
> BIT(DMA_MEM_TO_DEV);
> +	if (drvdata->flags & FSL_EDMA_DRV_DEV_TO_DEV)
> +		fsl_edma->dma_dev.directions |= BIT(DMA_DEV_TO_DEV);
> +
> +	fsl_edma->dma_dev.copy_align = drvdata->flags &
> FSL_EDMA_DRV_ALIGN_64BYTE ?
> +					DMAENGINE_ALIGN_64_BYTES :
> +					DMAENGINE_ALIGN_32_BYTES;
> 
> -	fsl_edma->dma_dev.copy_align = DMAENGINE_ALIGN_32_BYTES;
>  	/* Per worst case 'nbytes = 1' take CITER as the max_seg_size */
>  	dma_set_max_seg_size(fsl_edma->dma_dev.dev, 0x3fff);
> 
> +	fsl_edma->dma_dev.residue_granularity =
> +DMA_RESIDUE_GRANULARITY_SEGMENT;
> +
>  	platform_set_drvdata(pdev, fsl_edma);
> 
>  	ret = dma_async_device_register(&fsl_edma->dma_dev);
> @@ -359,7 +586,9 @@ static int fsl_edma_probe(struct platform_device
> *pdev)
>  		return ret;
>  	}
> 
> -	ret = of_dma_controller_register(np, fsl_edma_xlate, fsl_edma);
> +	ret = of_dma_controller_register(np,
> +			drvdata->flags & FSL_EDMA_DRV_SPLIT_REG ? fsl_edma3_xlate :
> fsl_edma_xlate,
> +			fsl_edma);
>  	if (ret) {
>  		dev_err(&pdev->dev,
>  			"Can't register Freescale eDMA of_dma. (%d)\n", ret); @@
> -368,7 +597,8 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  	}
> 
>  	/* enable round robin arbitration */
> -	edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
> +	if (!(drvdata->flags & FSL_EDMA_DRV_SPLIT_REG))
> +		edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
> 
>  	return 0;
>  }
> --
> 2.34.1


  reply	other threads:[~2023-06-02  9:41 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-01 14:40 [PATCH v3 00/12] dmaengine: edma: add freescale edma v3 support Frank Li
2023-06-01 14:40 ` [PATCH v3 01/12] dmaengine: fsl-edma: clean up EXPORT_SYMBOL_GPL in fsl-edma-common.c Frank Li
2023-06-01 14:40 ` [PATCH v3 02/12] dmaengine: fsl-edma: clean up fsl_edma_irq_exit() Frank Li
2023-06-01 14:40 ` [PATCH v3 03/12] dmaengine: fsl-edma: transition from bool fields to bitmask flags in drvdata Frank Li
2023-06-01 14:40 ` [PATCH v3 04/12] dmaengine: fsl-edma: Remove enum edma_version Frank Li
2023-06-01 14:41 ` [PATCH v3 05/12] dmaengine: fsl-edma: move common IRQ handler to common.c Frank Li
2023-06-01 14:41 ` [PATCH v3 06/12] dmaengine: fsl-edma: simply ATTR_DSIZE and ATTR_SSIZE by using ffs() Frank Li
2023-06-01 14:41 ` [PATCH v3 07/12] dmaengine: fsl-edma: refactor using devm_clk_get_enabled Frank Li
2023-06-01 14:41 ` [PATCH v3 08/12] dmaengine: fsl-edma: move clearing of register interrupt into setup_irq function Frank Li
2023-06-01 14:41 ` [PATCH v3 09/12] dmaengine: fsl-edma: refactor chan_name setup and safety Frank Li
2023-06-01 14:41 ` [PATCH v3 10/12] dmaengine: fsl-edma: move tcd into struct fsl_dma_chan Frank Li
2023-06-01 14:41 ` [PATCH v3 11/12] dmaengine: fsl-edma: integrate v3 support Frank Li
2023-06-02  9:41   ` Joy Zou [this message]
2023-06-02 21:39     ` Frank Li
2023-06-01 14:41 ` [PATCH v3 12/12] dt-bindings: fsl-dma: fsl-edma: add edma3 compatible string Frank Li
2023-06-02  8:30   ` Krzysztof Kozlowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AM6PR04MB59252F1C1BE15C61911C60EEE14EA@AM6PR04MB5925.eurprd04.prod.outlook.com \
    --to=joy.zou@nxp.com \
    --cc=aisheng.dong@nxp.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dmaengine@vger.kernel.org \
    --cc=frank.li@nxp.com \
    --cc=imx@lists.linux.dev \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peng.fan@nxp.com \
    --cc=robh+dt@kernel.org \
    --cc=shenwei.wang@nxp.com \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.