RE: [PATCH v3 6/6] dmaengine: fsl-edma: integrate TCD64 support for i.MX95

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi frank,
> -----Original Message-----
> From: Frank Li <frank.li@xxxxxxx>
> Sent: 2023年11月28日 6:56
> To: Frank Li <frank.li@xxxxxxx>; vkoul@xxxxxxxxxx
> Cc: devicetree@xxxxxxxxxxxxxxx; dmaengine@xxxxxxxxxxxxxxx;
> imx@xxxxxxxxxxxxxxx; Joy Zou <joy.zou@xxxxxxx>;
> krzysztof.kozlowski+dt@xxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; Peng Fan
> <peng.fan@xxxxxxx>; robh+dt@xxxxxxxxxx; Shenwei Wang
> <shenwei.wang@xxxxxxx>
> Subject: [PATCH v3 6/6] dmaengine: fsl-edma: integrate TCD64 support for
> i.MX95
> 
> In i.MX95's edma version 5, the TCD structure is extended to support 64-bit
> addresses for fields like saddr and daddr. To prevent code duplication, employ
> help macros to handle the fields, as the field names remain the same between
> TCD and TCD64.
> 
> Change local variables related to TCD addresses from 'u32' to 'dma_addr_t'
> to accept 64-bit DMA addresses.
> 
> Change 'vtcd' type to 'void *' to avoid direct use. Use helper macros to access
> the TCD fields correctly.
> 
> Call 'dma_set_mask_and_coherent(64)' when TCD64 is supported.
> 
> Signed-off-by: Frank Li <Frank.Li@xxxxxxx>
> ---
>  drivers/dma/fsl-edma-common.c |  34 ++++---
> drivers/dma/fsl-edma-common.h | 165
> +++++++++++++++++++++++++++-------
>  drivers/dma/fsl-edma-main.c   |  14 +++
>  3 files changed, 170 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/dma/fsl-edma-common.c
> b/drivers/dma/fsl-edma-common.c index 65f466ab9d4da..c8acff09308fd
> 100644
> --- a/drivers/dma/fsl-edma-common.c
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -351,7 +351,7 @@ static size_t fsl_edma_desc_residue(struct
> fsl_edma_chan *fsl_chan,  {
>  	struct fsl_edma_desc *edesc = fsl_chan->edesc;
>  	enum dma_transfer_direction dir = edesc->dirn;
> -	dma_addr_t cur_addr, dma_addr;
> +	dma_addr_t cur_addr, dma_addr, old_addr;
>  	size_t len, size;
>  	u32 nbytes = 0;
>  	int i;
> @@ -367,10 +367,16 @@ static size_t fsl_edma_desc_residue(struct
> fsl_edma_chan *fsl_chan,
>  	if (!in_progress)
>  		return len;
> 
> -	if (dir == DMA_MEM_TO_DEV)
> -		cur_addr = edma_read_tcdreg(fsl_chan, saddr);
> -	else
> -		cur_addr = edma_read_tcdreg(fsl_chan, daddr);
> +	/* 64bit read is not atomic, need read retry when high 32bit changed */
> +	do {
> +		if (dir == DMA_MEM_TO_DEV) {
> +			old_addr = edma_read_tcdreg(fsl_chan, saddr);
> +			cur_addr = edma_read_tcdreg(fsl_chan, saddr);
> +		} else {
> +			old_addr = edma_read_tcdreg(fsl_chan, daddr);
> +			cur_addr = edma_read_tcdreg(fsl_chan, daddr);
> +		}
> +	} while (upper_32_bits(cur_addr) != upper_32_bits(old_addr));
> 
>  	/* figure out the finished and calculate the residue */
>  	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { @@ -426,8 +432,7 @@
> enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
>  	return fsl_chan->status;
>  }
> 
> -static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
> -				  struct fsl_edma_hw_tcd *tcd)
> +static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, void
> +*tcd)
>  {
>  	u16 csr = 0;
> 
> @@ -478,9 +483,9 @@ static void fsl_edma_set_tcd_regs(struct
> fsl_edma_chan *fsl_chan,
> 
>  static inline
>  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,
> +		       struct fsl_edma_hw_tcd *tcd, dma_addr_t src, dma_addr_t
> dst,
> +		       u16 attr, u16 soff, u32 nbytes, dma_addr_t slast, u16 citer,
> +		       u16 biter, u16 doff, dma_addr_t dlast_sga, bool major_int,
>  		       bool disable_req, bool enable_sg)  {
>  	struct dma_slave_config *cfg = &fsl_chan->cfg; @@ -581,8 +586,9 @@
> struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
>  	dma_addr_t dma_buf_next;
>  	bool major_int = true;
>  	int sg_len, i;
> -	u32 src_addr, dst_addr, last_sg, nbytes;
> +	dma_addr_t src_addr, dst_addr, last_sg;
>  	u16 soff, doff, iter;
> +	u32 nbytes;
> 
>  	if (!is_slave_direction(direction))
>  		return NULL;
> @@ -654,8 +660,9 @@ struct dma_async_tx_descriptor
> *fsl_edma_prep_slave_sg(
>  	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
>  	struct fsl_edma_desc *fsl_desc;
>  	struct scatterlist *sg;
> -	u32 src_addr, dst_addr, last_sg, nbytes;
> +	dma_addr_t src_addr, dst_addr, last_sg;
>  	u16 soff, doff, iter;
> +	u32 nbytes;
>  	int i;
> 
>  	if (!is_slave_direction(direction))
> @@ -804,7 +811,8 @@ int fsl_edma_alloc_chan_resources(struct dma_chan
> *chan)
>  	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> 
>  	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
> -				sizeof(struct fsl_edma_hw_tcd),
> +				fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
> +				sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct
> fsl_edma_hw_tcd),
>  				32, 0);
>  	return 0;
>  }
> diff --git a/drivers/dma/fsl-edma-common.h
> b/drivers/dma/fsl-edma-common.h index 4f39a548547a6..6afceb9fded1b
> 100644
> --- a/drivers/dma/fsl-edma-common.h
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -87,6 +87,20 @@ struct fsl_edma_hw_tcd {
>  	__le16	biter;
>  };
> 
> +struct fsl_edma_hw_tcd64 {
> +	__le64  saddr;
> +	__le16  soff;
> +	__le16  attr;
> +	__le32  nbytes;
> +	__le64  slast;
> +	__le64  daddr;
> +	__le64  dlast_sga;
> +	__le16  doff;
> +	__le16  citer;
> +	__le16  csr;
> +	__le16  biter;
> +} __packed;
> +
>  struct fsl_edma3_ch_reg {
>  	__le32	ch_csr;
>  	__le32	ch_es;
> @@ -96,7 +110,10 @@ struct fsl_edma3_ch_reg {
>  	__le32	ch_mux;
>  	__le32  ch_mattr; /* edma4, reserved for edma3 */
>  	__le32  ch_reserved;
> -	struct fsl_edma_hw_tcd tcd;
> +	union {
> +		struct fsl_edma_hw_tcd tcd;
> +		struct fsl_edma_hw_tcd tcd64;
> +	};
>  } __packed; 
The tcd64 should be fsl_edma_hw_tcd64?
BR
Joy Zou 
> 
>  /*
> @@ -125,7 +142,7 @@ struct edma_regs {
> 
>  struct fsl_edma_sw_tcd {
>  	dma_addr_t			ptcd;
> -	struct fsl_edma_hw_tcd		*vtcd;
> +	void				*vtcd;
>  };
> 
>  struct fsl_edma_chan {
> @@ -144,7 +161,7 @@ struct fsl_edma_chan {
>  	u32				dma_dev_size;
>  	enum dma_data_direction		dma_dir;
>  	char				chan_name[32];
> -	struct fsl_edma_hw_tcd __iomem *tcd;
> +	void __iomem			*tcd;
>  	void __iomem			*mux_addr;
>  	u32				real_count;
>  	struct work_struct		issue_worker;
> @@ -188,6 +205,7 @@ struct fsl_edma_desc {
>  #define FSL_EDMA_DRV_CLEAR_DONE_E_SG	BIT(13)
>  /* Need clean CHn_CSR DONE before enable TCD's MAJORELINK */
>  #define FSL_EDMA_DRV_CLEAR_DONE_E_LINK	BIT(14)
> +#define FSL_EDMA_DRV_TCD64		BIT(15)
> 
>  #define FSL_EDMA_DRV_EDMA3	(FSL_EDMA_DRV_SPLIT_REG |	\
>  				 FSL_EDMA_DRV_BUS_8BYTE |	\
> @@ -231,18 +249,61 @@ struct fsl_edma_engine {
>  	struct fsl_edma_chan	chans[] __counted_by(n_chans);
>  };
> 
> -#define edma_read_tcdreg(chan, __name)				\
> -(sizeof(chan->tcd->__name) == sizeof(u32) ?			\
> -	edma_readl(chan->edma, &chan->tcd->__name) :		\
> -	edma_readw(chan->edma, &chan->tcd->__name))
> +#define edma_read_tcdreg_c(chan, _tcd,  __name)				\
> +(sizeof((_tcd)->__name) == sizeof(u64) ?				\
> +	edma_readq(chan->edma, &(_tcd)->__name) :			\
> +		((sizeof((_tcd)->__name) == sizeof(u32)) ?		\
> +			edma_readl(chan->edma, &(_tcd)->__name) :	\
> +			edma_readw(chan->edma, &(_tcd)->__name)		\
> +		))
> +
> +#define edma_read_tcdreg(chan, __name)
> 	\
> +((fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) ?
> 	\
> +	edma_read_tcdreg_c(chan, ((struct fsl_edma_hw_tcd64 __iomem
> *)chan->tcd), __name) :	\
> +	edma_read_tcdreg_c(chan, ((struct fsl_edma_hw_tcd __iomem
> *)chan->tcd), __name)		\
> +)
> +
> +#define edma_write_tcdreg_c(chan, _tcd, _val, __name)				\
> +do {										\
> +	switch (sizeof(_tcd->__name)) {						\
> +	case sizeof(u64):							\
> +		edma_writeq(chan->edma, (u64 __force)_val, &_tcd->__name);	\
> +		break;								\
> +	case sizeof(u32):							\
> +		edma_writel(chan->edma, (u32 __force)_val, &_tcd->__name);	\
> +		break;								\
> +	case sizeof(u16):							\
> +		edma_writew(chan->edma, (u16 __force)_val, &_tcd->__name);	\
> +		break;								\
> +	case sizeof(u8):							\
> +		edma_writeb(chan->edma, (u8 __force)_val, &_tcd->__name);	\
> +		break;								\
> +	}									\
> +} while (0)
> 
> -#define edma_write_tcdreg(chan, val, __name)			\
> -(sizeof(chan->tcd->__name) == sizeof(u32) ?			\
> -	edma_writel(chan->edma, (u32 __force)val, &chan->tcd->__name) :	\
> -	edma_writew(chan->edma, (u16 __force)val, &chan->tcd->__name))
> +#define edma_write_tcdreg(chan, val, __name)
> \
> +do {												   \
> +	struct fsl_edma_hw_tcd64 __iomem *tcd64_r = (struct
> fsl_edma_hw_tcd64 __iomem *)chan->tcd; \
> +	struct fsl_edma_hw_tcd __iomem *tcd_r = (struct fsl_edma_hw_tcd
> __iomem *)chan->tcd;	   \
> +												   \
> +	if (fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64)
> 	   \
> +		edma_write_tcdreg_c(chan, tcd64_r, val, __name);
> \
> +	else											   \
> +		edma_write_tcdreg_c(chan, tcd_r, val, __name);
> \
> +} while (0)
> 
> -#define edma_cp_tcd_to_reg(chan, __tcd, __name)			\
> -	edma_write_tcdreg(chan, __tcd->__name, __name)
> +#define edma_cp_tcd_to_reg(chan, __tcd, __name)
> 	   \
> +do {	\
> +	struct fsl_edma_hw_tcd64 __iomem *tcd64_r = (struct
> fsl_edma_hw_tcd64 __iomem *)chan->tcd; \
> +	struct fsl_edma_hw_tcd __iomem *tcd_r = (struct fsl_edma_hw_tcd
> __iomem *)chan->tcd;	   \
> +	struct fsl_edma_hw_tcd64 *tcd64_m = (struct fsl_edma_hw_tcd64
> *)__tcd;			   \
> +	struct fsl_edma_hw_tcd *tcd_m = (struct fsl_edma_hw_tcd *)__tcd;
> 	   \
> +												   \
> +	if (fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64)
> 	   \
> +		edma_write_tcdreg_c(chan, tcd64_r,  tcd64_m->__name, __name);
> 		   \
> +	else											   \
> +		edma_write_tcdreg_c(chan, tcd_r, tcd_m->__name, __name);
> 	   \
> +} while (0)
> 
>  #define edma_readl_chreg(chan, __name)				\
>  	edma_readl(chan->edma,					\
> @@ -254,24 +315,41 @@ struct fsl_edma_engine {
>  		   (void __iomem *)&(container_of(((__force void *)chan->tcd),\
>  						  struct fsl_edma3_ch_reg, tcd)->__name))
> 
> -#define fsl_edma_get_tcd(_chan, _tcd, _field) ((_tcd)->_field)
> -
> -#define fsl_edma_le_to_cpu(x)					\
> -(sizeof(x) == sizeof(u32) ? le32_to_cpu((__force __le32)(x)) :
> le16_to_cpu((__force __le16)(x)))
> -
> -#define fsl_edma_get_tcd_to_cpu(_chan, _tcd, _field)		\
> -fsl_edma_le_to_cpu(fsl_edma_get_tcd(_chan, _tcd, _field))
> +#define fsl_edma_get_tcd(_chan, _tcd, _field)			\
> +(fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64 ? (((struct
> fsl_edma_hw_tcd64 *)_tcd)->_field) : \
> +						 (((struct fsl_edma_hw_tcd *)_tcd)->_field))
> +
> +#define fsl_edma_le_to_cpu(x)						\
> +(sizeof(x) == sizeof(u64) ? le64_to_cpu((__force __le64)(x)) :		\
> +	(sizeof(x) == sizeof(u32) ? le32_to_cpu((__force __le32)(x)) :	\
> +				    le16_to_cpu((__force __le16)(x))))
> +
> +#define fsl_edma_get_tcd_to_cpu(_chan, _tcd, _field)				\
> +(fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64 ?				\
> +	fsl_edma_le_to_cpu(((struct fsl_edma_hw_tcd64 *)_tcd)->_field) :	\
> +	fsl_edma_le_to_cpu(((struct fsl_edma_hw_tcd *)_tcd)->_field))
> +
> +#define fsl_edma_set_tcd_to_le_c(_tcd, _val, _field)					\
> +do {											\
> +	switch (sizeof((_tcd)->_field)) {						\
> +	case sizeof(u64):								\
> +		*(__force __le64 *)(&((_tcd)->_field)) = cpu_to_le64(_val);		\
> +		break;									\
> +	case sizeof(u32):								\
> +		*(__force __le32 *)(&((_tcd)->_field)) = cpu_to_le32(_val);		\
> +		break;									\
> +	case sizeof(u16):								\
> +		*(__force __le16 *)(&((_tcd)->_field)) = cpu_to_le16(_val);		\
> +		break;									\
> +	}										\
> +} while (0)
> 
> -#define fsl_edma_set_tcd_to_le(_fsl_chan, _tcd, _val, _field)			\
> -do {										\
> -	switch (sizeof((_tcd)->_field)) {					\
> -	case sizeof(u32):							\
> -		*(__force __le32 *)(&((_tcd)->_field)) = cpu_to_le32(_val);	\
> -		break;								\
> -	case sizeof(u16):							\
> -		*(__force __le16 *)(&((_tcd)->_field)) = cpu_to_le16(_val);	\
> -		break;								\
> -	}									\
> +#define fsl_edma_set_tcd_to_le(_chan, _tcd, _val, _field)	\
> +do {								\
> +	if (fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64)	\
> +		fsl_edma_set_tcd_to_le_c((struct fsl_edma_hw_tcd64 *)_tcd, _val,
> _field);	\
> +	else											\
> +		fsl_edma_set_tcd_to_le_c((struct fsl_edma_hw_tcd *)_tcd, _val,
> _field);		\
>  } while (0)
> 
>  /*
> @@ -280,6 +358,21 @@ do {
> 	\
>   * For the big-endian IP module, the offset for 8-bit or 16-bit registers
>   * should also be swapped opposite to that in little-endian IP.
>   */
> +static inline u64 edma_readq(struct fsl_edma_engine *edma, void __iomem
> +*addr) {
> +	u64 l, h;
> +
> +	if (edma->big_endian) {
> +		l = ioread32be(addr);
> +		h = ioread32be(addr + 4);
> +	} else {
> +		l = ioread32(addr);
> +		h = ioread32(addr + 4);
> +	}
> +
> +	return (h << 32) | l;
> +}
> +
>  static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem
> *addr)  {
>  	if (edma->big_endian)
> @@ -325,6 +418,18 @@ static inline void edma_writel(struct
> fsl_edma_engine *edma,
>  		iowrite32(val, addr);
>  }
> 
> +static inline void edma_writeq(struct fsl_edma_engine *edma,
> +			       u64 val, void __iomem *addr)
> +{
> +	if (edma->big_endian) {
> +		iowrite32be(val & 0xFFFFFFFF, addr);
> +		iowrite32be(val >> 32, addr + 4);
> +	} else {
> +		iowrite32(val & 0xFFFFFFFF, addr);
> +		iowrite32(val >> 32, addr + 4);
> +	}
> +}
> +
>  static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
> {
>  	return container_of(chan, struct fsl_edma_chan, vchan.chan); diff --git
> a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index
> d767c89973b69..c2c0c3effc8cb 100644
> --- a/drivers/dma/fsl-edma-main.c
> +++ b/drivers/dma/fsl-edma-main.c
> @@ -364,6 +364,16 @@ static struct fsl_edma_drvdata imx93_data4 = {
>  	.setup_irq = fsl_edma3_irq_init,
>  };
> 
> +static struct fsl_edma_drvdata imx95_data5 = {
> +	.flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK |
> FSL_EDMA_DRV_EDMA4 |
> +		 FSL_EDMA_DRV_TCD64,
> +	.chreg_space_sz = 0x8000,
> +	.chreg_off = 0x10000,
> +	.mux_off = 0x200,
> +	.mux_skip = sizeof(u32),
> +	.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}, @@ -372,6
> +382,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = {
>  	{ .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data},
>  	{ .compatible = "fsl,imx93-edma3", .data = &imx93_data3},
>  	{ .compatible = "fsl,imx93-edma4", .data = &imx93_data4},
> +	{ .compatible = "fsl,imx95-edma5", .data = &imx95_data5},
>  	{ /* sentinel */ }
>  };
>  MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); @@ -513,6 +524,9 @@ static
> int fsl_edma_probe(struct platform_device *pdev)
>  			return ret;
>  	}
> 
> +	if (drvdata->flags & FSL_EDMA_DRV_TCD64)
> +		dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
> +
>  	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];
> --
> 2.34.1





[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux PCI]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux