dmaengine: dw-axi-dmac: Add StarFive JH7100 support
[platform/kernel/linux-starfive.git] / drivers / dma / dw-axi-dmac / dw-axi-dmac-platform.c
index a183d93..b38157a 100644 (file)
@@ -86,7 +86,7 @@ static inline void axi_chan_config_write(struct axi_dma_chan *chan,
 
        cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
                  config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
-       if (chan->chip->dw->hdata->reg_map_8_channels) {
+       if (!IS_ENABLED(CONFIG_SOC_STARFIVE) && chan->chip->dw->hdata->reg_map_8_channels) {
                cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
                         config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
                         config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
@@ -377,11 +377,13 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
        u32 irq_mask;
        u8 lms = 0; /* Select AXI0 master for LLI fetching */
 
+       chan->is_err = false;
        if (unlikely(axi_chan_is_hw_enable(chan))) {
                dev_err(chan2dev(chan), "%s is non-idle!\n",
                        axi_chan_name(chan));
 
-               return;
+               axi_chan_disable(chan);
+               chan->is_err = true;
        }
 
        axi_dma_enable(chan->chip);
@@ -670,8 +672,13 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
 
        hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
 
+#ifdef CONFIG_SOC_STARFIVE
+       ctllo |= DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_DST_MSIZE_POS |
+                DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_SRC_MSIZE_POS;
+#else
        ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
                 DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
+#endif
        hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
 
        set_desc_src_master(hw_desc);
@@ -1018,6 +1025,20 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
 
        /* The bad descriptor currently is in the head of vc list */
        vd = vchan_next_desc(&chan->vc);
+       if (!vd) {
+               dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n",
+                       axi_chan_name(chan));
+               goto out;
+       }
+
+       if (chan->is_err) {
+               struct axi_dma_desc *desc = vd_to_axi_desc(vd);
+
+               axi_chan_block_xfer_start(chan, desc);
+               chan->is_err = false;
+               goto out;
+       }
+
        /* Remove the completed descriptor from issued list */
        list_del(&vd->node);
 
@@ -1032,6 +1053,7 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
        /* Try to restart the controller */
        axi_chan_start_first_queued(chan);
 
+out:
        spin_unlock_irqrestore(&chan->vc.lock, flags);
 }
 
@@ -1473,7 +1495,11 @@ static int dw_probe(struct platform_device *pdev)
         * Therefore, set constraint to 1024 * 4.
         */
        dw->dma.dev->dma_parms = &dw->dma_parms;
+#ifdef CONFIG_SOC_STARFIVE
+       dma_set_max_seg_size(&pdev->dev, DMAC_MAX_BLK_SIZE);
+#else
        dma_set_max_seg_size(&pdev->dev, MAX_BLOCK_SIZE);
+#endif
        platform_set_drvdata(pdev, chip);
 
        pm_runtime_enable(chip->dev);