> 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