RE: [PATCH v4 5/7] dmaengine: dw-axi-dmac: Support hardware quirks

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

 



> Adds separate dma hardware descriptor setup for JH8100 hardware quirks.
> JH8100 engine uses AXI1 master for data transfer but current dma driver is
> hardcoded to use AXI0 only. The FIFO offset needs to be incremented due to
> hardware limitations.
> 
> Signed-off-by: Jia Jie Ho <jiajie.ho@xxxxxxxxxxxxxxxx>
> ---
>  .../dma/dw-axi-dmac/dw-axi-dmac-platform.c    | 32 ++++++++++++++++---
>  drivers/dma/dw-axi-dmac/dw-axi-dmac.h         |  2 ++
>  include/linux/dma/dw_axi.h                    | 11 +++++++
>  3 files changed, 40 insertions(+), 5 deletions(-)  create mode 100644
> include/linux/dma/dw_axi.h
> 
> diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> index a86a81ff0caa..684cabe33c7d 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> @@ -647,6 +647,7 @@ static void set_desc_dest_master(struct
> axi_dma_hw_desc *hw_desc,
> 
>  static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
>  				  struct axi_dma_hw_desc *hw_desc,
> +				  struct axi_dma_desc *desc,
>  				  dma_addr_t mem_addr, size_t len)
>  {
>  	unsigned int data_width = BIT(chan->chip->dw->hdata-
> >m_data_width);
> @@ -655,6 +656,8 @@ static int dw_axi_dma_set_hw_desc(struct
> axi_dma_chan *chan,
>  	dma_addr_t device_addr;
>  	size_t axi_block_ts;
>  	size_t block_ts;
> +	bool hw_quirks = chan->quirks & DWAXIDMAC_STARFIVE_SM_ALGO;
> +	u32 val;
>  	u32 ctllo, ctlhi;
>  	u32 burst_len;
> 
> @@ -675,7 +678,8 @@ static int dw_axi_dma_set_hw_desc(struct
> axi_dma_chan *chan,
>  		device_addr = chan->config.dst_addr;
>  		ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
>  			mem_width << CH_CTL_L_SRC_WIDTH_POS |
> -			DWAXIDMAC_CH_CTL_L_NOINC <<
> CH_CTL_L_DST_INC_POS |
> +			(hw_quirks ? DWAXIDMAC_CH_CTL_L_INC <<
> CH_CTL_L_DST_INC_POS :
> +				     DWAXIDMAC_CH_CTL_L_NOINC <<
> CH_CTL_L_DST_INC_POS) |
>  			DWAXIDMAC_CH_CTL_L_INC <<
> CH_CTL_L_SRC_INC_POS;
>  		block_ts = len >> mem_width;
>  		break;
> @@ -685,7 +689,8 @@ static int dw_axi_dma_set_hw_desc(struct
> axi_dma_chan *chan,
>  		ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
>  			mem_width << CH_CTL_L_DST_WIDTH_POS |
>  			DWAXIDMAC_CH_CTL_L_INC <<
> CH_CTL_L_DST_INC_POS |
> -			DWAXIDMAC_CH_CTL_L_NOINC <<
> CH_CTL_L_SRC_INC_POS;
> +			(hw_quirks ? DWAXIDMAC_CH_CTL_L_INC <<
> CH_CTL_L_SRC_INC_POS :
> +				     DWAXIDMAC_CH_CTL_L_NOINC <<
> CH_CTL_L_SRC_INC_POS);
>  		block_ts = len >> reg_width;
>  		break;
>  	default:
> @@ -726,6 +731,17 @@ static int dw_axi_dma_set_hw_desc(struct
> axi_dma_chan *chan,
> 
>  	set_desc_src_master(hw_desc);
> 
> +	if (hw_quirks) {
> +		if (chan->direction == DMA_MEM_TO_DEV) {
> +			set_desc_dest_master(hw_desc, desc);
> +		} else {
> +			/* Select AXI1 for src master */
> +			val = le32_to_cpu(hw_desc->lli->ctl_lo);
> +			val |= CH_CTL_L_SRC_MAST;
> +			hw_desc->lli->ctl_lo = cpu_to_le32(val);
> +		}
> +	}
> +
>  	hw_desc->len = len;
>  	return 0;
>  }
> @@ -802,8 +818,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan
> *dchan, dma_addr_t dma_addr,
>  	for (i = 0; i < total_segments; i++) {
>  		hw_desc = &desc->hw_desc[i];
> 
> -		status = dw_axi_dma_set_hw_desc(chan, hw_desc, src_addr,
> -						segment_len);
> +		status = dw_axi_dma_set_hw_desc(chan, hw_desc, NULL,
> +						src_addr, segment_len);
>  		if (status < 0)
>  			goto err_desc_get;
> 
> @@ -885,7 +901,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan
> *dchan, struct scatterlist *sgl,
> 
>  		do {
>  			hw_desc = &desc->hw_desc[loop++];
> -			status = dw_axi_dma_set_hw_desc(chan, hw_desc,
> mem, segment_len);
> +			status = dw_axi_dma_set_hw_desc(chan, hw_desc,
> desc,
> +							mem, segment_len);
>  			if (status < 0)
>  				goto err_desc_get;
> 
> @@ -1023,8 +1040,13 @@ static int dw_axi_dma_chan_slave_config(struct
> dma_chan *dchan,
>  					struct dma_slave_config *config)
>  {
>  	struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
> +	struct dw_axi_peripheral_config *periph = config->peripheral_config;
> 
>  	memcpy(&chan->config, config, sizeof(*config));
> +	if (config->peripheral_size == sizeof(*periph))
> +		chan->quirks = periph->quirks;
> +	else
> +		chan->quirks = 0;
> 
>  	return 0;
>  }
> diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-
> dmac/dw-axi-dmac.h
> index 454904d99654..043d7eb7cb67 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
> @@ -14,6 +14,7 @@
>  #include <linux/clk.h>
>  #include <linux/device.h>
>  #include <linux/dmaengine.h>
> +#include <linux/dma/dw_axi.h>
>  #include <linux/types.h>
> 
>  #include "../virt-dma.h"
> @@ -50,6 +51,7 @@ struct axi_dma_chan {
>  	struct dma_slave_config		config;
>  	enum dma_transfer_direction	direction;
>  	bool				cyclic;
> +	u32				quirks;
>  	/* these other elements are all protected by vc.lock */
>  	bool				is_paused;
>  };
> diff --git a/include/linux/dma/dw_axi.h b/include/linux/dma/dw_axi.h new
> file mode 100644 index 000000000000..fd49152869a4
> --- /dev/null
> +++ b/include/linux/dma/dw_axi.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __LINUX_DMA_DW_AXI_H
> +#define __LINUX_DMA_DW_AXI_H
> +
> +#include <linux/types.h>
> +
> +struct dw_axi_peripheral_config {
> +#define DWAXIDMAC_STARFIVE_SM_ALGO	BIT(0)
> +	u32 quirks;
> +};
> +#endif /* __LINUX_DMA_DW_AXI_H */
> --
> 2.34.1

Hi Eugeniy/Vinod,
Could you please help review this patch?

Thanks,
Jia Jie





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux