2024-05-08 02:27:51

by Jia Jie Ho

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

> 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 <[email protected]>
> ---
> .../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