Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
| 2 | /* |
| 3 | * Copyright 2013-2014 Freescale Semiconductor, Inc. |
| 4 | * Copyright 2018 Angelo Dureghello <angelo@sysam.it> |
| 5 | */ |
| 6 | #ifndef _FSL_EDMA_COMMON_H_ |
| 7 | #define _FSL_EDMA_COMMON_H_ |
| 8 | |
Laurentiu Tudor | 0fa89f9 | 2019-01-18 12:06:23 +0200 | [diff] [blame] | 9 | #include <linux/dma-direction.h> |
Robin Gong | af80272 | 2019-06-25 17:43:19 +0800 | [diff] [blame] | 10 | #include <linux/platform_device.h> |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 11 | #include "virt-dma.h" |
| 12 | |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 13 | #define EDMA_CR_EDBG BIT(1) |
| 14 | #define EDMA_CR_ERCA BIT(2) |
| 15 | #define EDMA_CR_ERGA BIT(3) |
| 16 | #define EDMA_CR_HOE BIT(4) |
| 17 | #define EDMA_CR_HALT BIT(5) |
| 18 | #define EDMA_CR_CLM BIT(6) |
| 19 | #define EDMA_CR_EMLM BIT(7) |
| 20 | #define EDMA_CR_ECX BIT(16) |
| 21 | #define EDMA_CR_CX BIT(17) |
| 22 | |
Angelo Dureghello | 4d6d3a9 | 2018-08-19 19:27:15 +0200 | [diff] [blame] | 23 | #define EDMA_SEEI_SEEI(x) ((x) & GENMASK(4, 0)) |
| 24 | #define EDMA_CEEI_CEEI(x) ((x) & GENMASK(4, 0)) |
| 25 | #define EDMA_CINT_CINT(x) ((x) & GENMASK(4, 0)) |
| 26 | #define EDMA_CERR_CERR(x) ((x) & GENMASK(4, 0)) |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 27 | |
Angelo Dureghello | 4d6d3a9 | 2018-08-19 19:27:15 +0200 | [diff] [blame] | 28 | #define EDMA_TCD_ATTR_DSIZE(x) (((x) & GENMASK(2, 0))) |
| 29 | #define EDMA_TCD_ATTR_DMOD(x) (((x) & GENMASK(4, 0)) << 3) |
| 30 | #define EDMA_TCD_ATTR_SSIZE(x) (((x) & GENMASK(2, 0)) << 8) |
| 31 | #define EDMA_TCD_ATTR_SMOD(x) (((x) & GENMASK(4, 0)) << 11) |
| 32 | #define EDMA_TCD_ATTR_DSIZE_8BIT 0 |
| 33 | #define EDMA_TCD_ATTR_DSIZE_16BIT BIT(0) |
| 34 | #define EDMA_TCD_ATTR_DSIZE_32BIT BIT(1) |
| 35 | #define EDMA_TCD_ATTR_DSIZE_64BIT (BIT(0) | BIT(1)) |
Robin Gong | e142087 | 2020-06-30 00:59:58 +0800 | [diff] [blame] | 36 | #define EDMA_TCD_ATTR_DSIZE_32BYTE (BIT(2) | BIT(0)) |
Angelo Dureghello | 4d6d3a9 | 2018-08-19 19:27:15 +0200 | [diff] [blame] | 37 | #define EDMA_TCD_ATTR_SSIZE_8BIT 0 |
| 38 | #define EDMA_TCD_ATTR_SSIZE_16BIT (EDMA_TCD_ATTR_DSIZE_16BIT << 8) |
| 39 | #define EDMA_TCD_ATTR_SSIZE_32BIT (EDMA_TCD_ATTR_DSIZE_32BIT << 8) |
| 40 | #define EDMA_TCD_ATTR_SSIZE_64BIT (EDMA_TCD_ATTR_DSIZE_64BIT << 8) |
| 41 | #define EDMA_TCD_ATTR_SSIZE_32BYTE (EDMA_TCD_ATTR_DSIZE_32BYTE << 8) |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 42 | |
Angelo Dureghello | 4d6d3a9 | 2018-08-19 19:27:15 +0200 | [diff] [blame] | 43 | #define EDMA_TCD_CITER_CITER(x) ((x) & GENMASK(14, 0)) |
| 44 | #define EDMA_TCD_BITER_BITER(x) ((x) & GENMASK(14, 0)) |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 45 | |
| 46 | #define EDMA_TCD_CSR_START BIT(0) |
| 47 | #define EDMA_TCD_CSR_INT_MAJOR BIT(1) |
| 48 | #define EDMA_TCD_CSR_INT_HALF BIT(2) |
| 49 | #define EDMA_TCD_CSR_D_REQ BIT(3) |
| 50 | #define EDMA_TCD_CSR_E_SG BIT(4) |
| 51 | #define EDMA_TCD_CSR_E_LINK BIT(5) |
| 52 | #define EDMA_TCD_CSR_ACTIVE BIT(6) |
| 53 | #define EDMA_TCD_CSR_DONE BIT(7) |
| 54 | |
| 55 | #define EDMAMUX_CHCFG_DIS 0x0 |
| 56 | #define EDMAMUX_CHCFG_ENBL 0x80 |
| 57 | #define EDMAMUX_CHCFG_SOURCE(n) ((n) & 0x3F) |
| 58 | |
| 59 | #define DMAMUX_NR 2 |
| 60 | |
| 61 | #define FSL_EDMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ |
| 62 | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ |
| 63 | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ |
| 64 | BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) |
| 65 | enum fsl_edma_pm_state { |
| 66 | RUNNING = 0, |
| 67 | SUSPENDED, |
| 68 | }; |
| 69 | |
| 70 | struct fsl_edma_hw_tcd { |
| 71 | __le32 saddr; |
| 72 | __le16 soff; |
| 73 | __le16 attr; |
| 74 | __le32 nbytes; |
| 75 | __le32 slast; |
| 76 | __le32 daddr; |
| 77 | __le16 doff; |
| 78 | __le16 citer; |
| 79 | __le32 dlast_sga; |
| 80 | __le16 csr; |
| 81 | __le16 biter; |
| 82 | }; |
| 83 | |
Angelo Dureghello | 377eaf3 | 2018-08-19 19:27:14 +0200 | [diff] [blame] | 84 | /* |
| 85 | * These are iomem pointers, for both v32 and v64. |
| 86 | */ |
| 87 | struct edma_regs { |
| 88 | void __iomem *cr; |
| 89 | void __iomem *es; |
| 90 | void __iomem *erqh; |
| 91 | void __iomem *erql; /* aka erq on v32 */ |
| 92 | void __iomem *eeih; |
| 93 | void __iomem *eeil; /* aka eei on v32 */ |
| 94 | void __iomem *seei; |
| 95 | void __iomem *ceei; |
| 96 | void __iomem *serq; |
| 97 | void __iomem *cerq; |
| 98 | void __iomem *cint; |
| 99 | void __iomem *cerr; |
| 100 | void __iomem *ssrt; |
| 101 | void __iomem *cdne; |
| 102 | void __iomem *inth; |
| 103 | void __iomem *intl; |
| 104 | void __iomem *errh; |
| 105 | void __iomem *errl; |
| 106 | struct fsl_edma_hw_tcd __iomem *tcd; |
| 107 | }; |
| 108 | |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 109 | struct fsl_edma_sw_tcd { |
| 110 | dma_addr_t ptcd; |
| 111 | struct fsl_edma_hw_tcd *vtcd; |
| 112 | }; |
| 113 | |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 114 | struct fsl_edma_chan { |
| 115 | struct virt_dma_chan vchan; |
| 116 | enum dma_status status; |
| 117 | enum fsl_edma_pm_state pm_state; |
| 118 | bool idle; |
| 119 | u32 slave_id; |
| 120 | struct fsl_edma_engine *edma; |
| 121 | struct fsl_edma_desc *edesc; |
Vinod Koul | 0e819e35 | 2018-10-07 19:42:56 +0530 | [diff] [blame] | 122 | struct dma_slave_config cfg; |
| 123 | u32 attr; |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 124 | struct dma_pool *tcd_pool; |
Laurentiu Tudor | 0fa89f9 | 2019-01-18 12:06:23 +0200 | [diff] [blame] | 125 | dma_addr_t dma_dev_addr; |
| 126 | u32 dma_dev_size; |
| 127 | enum dma_data_direction dma_dir; |
Robin Gong | 232a7f1 | 2019-07-24 15:20:34 +0800 | [diff] [blame] | 128 | char chan_name[16]; |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 129 | }; |
| 130 | |
| 131 | struct fsl_edma_desc { |
| 132 | struct virt_dma_desc vdesc; |
| 133 | struct fsl_edma_chan *echan; |
| 134 | bool iscyclic; |
Vinod Koul | 0e819e35 | 2018-10-07 19:42:56 +0530 | [diff] [blame] | 135 | enum dma_transfer_direction dirn; |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 136 | unsigned int n_tcds; |
| 137 | struct fsl_edma_sw_tcd tcd[]; |
| 138 | }; |
| 139 | |
Angelo Dureghello | 377eaf3 | 2018-08-19 19:27:14 +0200 | [diff] [blame] | 140 | enum edma_version { |
Krzysztof Kozlowski | 3268555 | 2019-05-04 11:52:23 +0200 | [diff] [blame] | 141 | v1, /* 32ch, Vybrid, mpc57x, etc */ |
Angelo Dureghello | 377eaf3 | 2018-08-19 19:27:14 +0200 | [diff] [blame] | 142 | v2, /* 64ch Coldfire */ |
Robin Gong | 232a7f1 | 2019-07-24 15:20:34 +0800 | [diff] [blame] | 143 | v3, /* 32ch, i.mx7ulp */ |
Angelo Dureghello | 377eaf3 | 2018-08-19 19:27:14 +0200 | [diff] [blame] | 144 | }; |
| 145 | |
Robin Gong | af80272 | 2019-06-25 17:43:19 +0800 | [diff] [blame] | 146 | struct fsl_edma_drvdata { |
| 147 | enum edma_version version; |
| 148 | u32 dmamuxs; |
Robin Gong | 232a7f1 | 2019-07-24 15:20:34 +0800 | [diff] [blame] | 149 | bool has_dmaclk; |
Peng Ma | ed5a0ab | 2019-12-12 03:38:10 +0000 | [diff] [blame] | 150 | bool mux_swap; |
Robin Gong | af80272 | 2019-06-25 17:43:19 +0800 | [diff] [blame] | 151 | int (*setup_irq)(struct platform_device *pdev, |
| 152 | struct fsl_edma_engine *fsl_edma); |
| 153 | }; |
| 154 | |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 155 | struct fsl_edma_engine { |
| 156 | struct dma_device dma_dev; |
| 157 | void __iomem *membase; |
| 158 | void __iomem *muxbase[DMAMUX_NR]; |
| 159 | struct clk *muxclk[DMAMUX_NR]; |
Robin Gong | 232a7f1 | 2019-07-24 15:20:34 +0800 | [diff] [blame] | 160 | struct clk *dmaclk; |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 161 | struct mutex fsl_edma_mutex; |
Robin Gong | af80272 | 2019-06-25 17:43:19 +0800 | [diff] [blame] | 162 | const struct fsl_edma_drvdata *drvdata; |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 163 | u32 n_chans; |
| 164 | int txirq; |
| 165 | int errirq; |
| 166 | bool big_endian; |
Angelo Dureghello | 377eaf3 | 2018-08-19 19:27:14 +0200 | [diff] [blame] | 167 | struct edma_regs regs; |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 168 | struct fsl_edma_chan chans[]; |
| 169 | }; |
| 170 | |
| 171 | /* |
| 172 | * R/W functions for big- or little-endian registers: |
| 173 | * The eDMA controller's endian is independent of the CPU core's endian. |
| 174 | * For the big-endian IP module, the offset for 8-bit or 16-bit registers |
| 175 | * should also be swapped opposite to that in little-endian IP. |
| 176 | */ |
| 177 | static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) |
| 178 | { |
| 179 | if (edma->big_endian) |
| 180 | return ioread32be(addr); |
| 181 | else |
| 182 | return ioread32(addr); |
| 183 | } |
| 184 | |
| 185 | static inline void edma_writeb(struct fsl_edma_engine *edma, |
| 186 | u8 val, void __iomem *addr) |
| 187 | { |
| 188 | /* swap the reg offset for these in big-endian mode */ |
| 189 | if (edma->big_endian) |
| 190 | iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3)); |
| 191 | else |
| 192 | iowrite8(val, addr); |
| 193 | } |
| 194 | |
| 195 | static inline void edma_writew(struct fsl_edma_engine *edma, |
| 196 | u16 val, void __iomem *addr) |
| 197 | { |
| 198 | /* swap the reg offset for these in big-endian mode */ |
| 199 | if (edma->big_endian) |
| 200 | iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2)); |
| 201 | else |
| 202 | iowrite16(val, addr); |
| 203 | } |
| 204 | |
| 205 | static inline void edma_writel(struct fsl_edma_engine *edma, |
| 206 | u32 val, void __iomem *addr) |
| 207 | { |
| 208 | if (edma->big_endian) |
| 209 | iowrite32be(val, addr); |
| 210 | else |
| 211 | iowrite32(val, addr); |
| 212 | } |
| 213 | |
| 214 | static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan) |
| 215 | { |
| 216 | return container_of(chan, struct fsl_edma_chan, vchan.chan); |
| 217 | } |
| 218 | |
| 219 | static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd) |
| 220 | { |
| 221 | return container_of(vd, struct fsl_edma_desc, vdesc); |
| 222 | } |
| 223 | |
| 224 | void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan); |
| 225 | void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, |
| 226 | unsigned int slot, bool enable); |
| 227 | void fsl_edma_free_desc(struct virt_dma_desc *vdesc); |
| 228 | int fsl_edma_terminate_all(struct dma_chan *chan); |
| 229 | int fsl_edma_pause(struct dma_chan *chan); |
| 230 | int fsl_edma_resume(struct dma_chan *chan); |
| 231 | int fsl_edma_slave_config(struct dma_chan *chan, |
| 232 | struct dma_slave_config *cfg); |
| 233 | enum dma_status fsl_edma_tx_status(struct dma_chan *chan, |
| 234 | dma_cookie_t cookie, struct dma_tx_state *txstate); |
| 235 | struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic( |
| 236 | struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, |
| 237 | size_t period_len, enum dma_transfer_direction direction, |
| 238 | unsigned long flags); |
| 239 | struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg( |
| 240 | struct dma_chan *chan, struct scatterlist *sgl, |
| 241 | unsigned int sg_len, enum dma_transfer_direction direction, |
| 242 | unsigned long flags, void *context); |
| 243 | void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan); |
| 244 | void fsl_edma_issue_pending(struct dma_chan *chan); |
| 245 | int fsl_edma_alloc_chan_resources(struct dma_chan *chan); |
| 246 | void fsl_edma_free_chan_resources(struct dma_chan *chan); |
| 247 | void fsl_edma_cleanup_vchan(struct dma_device *dmadev); |
Angelo Dureghello | 377eaf3 | 2018-08-19 19:27:14 +0200 | [diff] [blame] | 248 | void fsl_edma_setup_regs(struct fsl_edma_engine *edma); |
Angelo Dureghello | 9d83152 | 2018-08-19 19:27:13 +0200 | [diff] [blame] | 249 | |
| 250 | #endif /* _FSL_EDMA_COMMON_H_ */ |