Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: fsl-edma: add i.mx7ulp edma2 version support

Add edma2 for i.mx7ulp by version v3, since v2 has already
been used by mcf-edma.
The big changes based on v1 are belows:
1. only one dmamux.
2. another clock dma_clk except dmamux clk.
3. 16 independent interrupts instead of only one interrupt for
all channels.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Link: https://lore.kernel.org/r/1563952834-7731-1-git-send-email-yibin.gong@nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Robin Gong and committed by
Vinod Koul
232a7f18 719e25db

+86 -1
+17 -1
drivers/dma/fsl-edma-common.c
··· 90 90 iowrite8(val8, addr + off); 91 91 } 92 92 93 + void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, 94 + u32 off, u32 slot, bool enable) 95 + { 96 + u32 val; 97 + 98 + if (enable) 99 + val = EDMAMUX_CHCFG_ENBL << 24 | slot; 100 + else 101 + val = EDMAMUX_CHCFG_DIS; 102 + 103 + iowrite32(val, addr + off * 4); 104 + } 105 + 93 106 void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, 94 107 unsigned int slot, bool enable) 95 108 { ··· 116 103 muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; 117 104 slot = EDMAMUX_CHCFG_SOURCE(slot); 118 105 119 - mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); 106 + if (fsl_chan->edma->drvdata->version == v3) 107 + mux_configure32(fsl_chan, muxaddr, ch_off, slot, enable); 108 + else 109 + mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); 120 110 } 121 111 EXPORT_SYMBOL_GPL(fsl_edma_chan_mux); 122 112
+4
drivers/dma/fsl-edma-common.h
··· 125 125 dma_addr_t dma_dev_addr; 126 126 u32 dma_dev_size; 127 127 enum dma_data_direction dma_dir; 128 + char chan_name[16]; 128 129 }; 129 130 130 131 struct fsl_edma_desc { ··· 140 139 enum edma_version { 141 140 v1, /* 32ch, Vybrid, mpc57x, etc */ 142 141 v2, /* 64ch Coldfire */ 142 + v3, /* 32ch, i.mx7ulp */ 143 143 }; 144 144 145 145 struct fsl_edma_drvdata { 146 146 enum edma_version version; 147 147 u32 dmamuxs; 148 + bool has_dmaclk; 148 149 int (*setup_irq)(struct platform_device *pdev, 149 150 struct fsl_edma_engine *fsl_edma); 150 151 }; ··· 156 153 void __iomem *membase; 157 154 void __iomem *muxbase[DMAMUX_NR]; 158 155 struct clk *muxclk[DMAMUX_NR]; 156 + struct clk *dmaclk; 159 157 struct mutex fsl_edma_mutex; 160 158 const struct fsl_edma_drvdata *drvdata; 161 159 u32 n_chans;
+65
drivers/dma/fsl-edma.c
··· 158 158 return 0; 159 159 } 160 160 161 + static int 162 + fsl_edma2_irq_init(struct platform_device *pdev, 163 + struct fsl_edma_engine *fsl_edma) 164 + { 165 + int i, ret, irq; 166 + int count; 167 + 168 + count = platform_irq_count(pdev); 169 + dev_dbg(&pdev->dev, "%s Found %d interrupts\r\n", __func__, count); 170 + if (count <= 2) { 171 + dev_err(&pdev->dev, "Interrupts in DTS not correct.\n"); 172 + return -EINVAL; 173 + } 174 + /* 175 + * 16 channel independent interrupts + 1 error interrupt on i.mx7ulp. 176 + * 2 channel share one interrupt, for example, ch0/ch16, ch1/ch17... 177 + * For now, just simply request irq without IRQF_SHARED flag, since 16 178 + * channels are enough on i.mx7ulp whose M4 domain own some peripherals. 179 + */ 180 + for (i = 0; i < count; i++) { 181 + irq = platform_get_irq(pdev, i); 182 + if (irq < 0) 183 + return -ENXIO; 184 + 185 + sprintf(fsl_edma->chans[i].chan_name, "eDMA2-CH%02d", i); 186 + 187 + /* The last IRQ is for eDMA err */ 188 + if (i == count - 1) 189 + ret = devm_request_irq(&pdev->dev, irq, 190 + fsl_edma_err_handler, 191 + 0, "eDMA2-ERR", fsl_edma); 192 + else 193 + ret = devm_request_irq(&pdev->dev, irq, 194 + fsl_edma_tx_handler, 0, 195 + fsl_edma->chans[i].chan_name, 196 + fsl_edma); 197 + if (ret) 198 + return ret; 199 + } 200 + 201 + return 0; 202 + } 203 + 161 204 static void fsl_edma_irq_exit( 162 205 struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) 163 206 { ··· 226 183 .setup_irq = fsl_edma_irq_init, 227 184 }; 228 185 186 + static struct fsl_edma_drvdata imx7ulp_data = { 187 + .version = v3, 188 + .dmamuxs = 1, 189 + .has_dmaclk = true, 190 + .setup_irq = fsl_edma2_irq_init, 191 + }; 192 + 229 193 static const struct of_device_id fsl_edma_dt_ids[] = { 230 194 { .compatible = "fsl,vf610-edma", .data = &vf610_data}, 195 + { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, 231 196 { /* sentinel */ } 232 197 }; 233 198 MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); ··· 282 231 283 232 fsl_edma_setup_regs(fsl_edma); 284 233 regs = &fsl_edma->regs; 234 + 235 + if (drvdata->has_dmaclk) { 236 + fsl_edma->dmaclk = devm_clk_get(&pdev->dev, "dma"); 237 + if (IS_ERR(fsl_edma->dmaclk)) { 238 + dev_err(&pdev->dev, "Missing DMA block clock.\n"); 239 + return PTR_ERR(fsl_edma->dmaclk); 240 + } 241 + 242 + ret = clk_prepare_enable(fsl_edma->dmaclk); 243 + if (ret) { 244 + dev_err(&pdev->dev, "DMA clk block failed.\n"); 245 + return ret; 246 + } 247 + } 285 248 286 249 for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) { 287 250 char clkname[32];