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

dmaengine: fsl-edma: integrate TCD64 support for i.MX95

In i.MX95's edma version 5, the TCD structure is extended to support 64-bit
addresses for fields like saddr and daddr. To prevent code duplication,
employ help macros to handle the fields, as the field names remain the same
between TCD and TCD64.

Change local variables related to TCD addresses from 'u32' to 'dma_addr_t'
to accept 64-bit DMA addresses.

Change 'vtcd' type to 'void *' to avoid direct use. Use helper macros to
access the TCD fields correctly.

Call 'dma_set_mask_and_coherent(64)' when TCD64 is supported.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20231221153528.1588049-7-Frank.Li@nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Frank Li and committed by
Vinod Koul
de7d9cb3 b7b8715b

+168 -41
+21 -13
drivers/dma/fsl-edma-common.c
··· 351 351 { 352 352 struct fsl_edma_desc *edesc = fsl_chan->edesc; 353 353 enum dma_transfer_direction dir = edesc->dirn; 354 - dma_addr_t cur_addr, dma_addr; 354 + dma_addr_t cur_addr, dma_addr, old_addr; 355 355 size_t len, size; 356 356 u32 nbytes = 0; 357 357 int i; ··· 367 367 if (!in_progress) 368 368 return len; 369 369 370 - if (dir == DMA_MEM_TO_DEV) 371 - cur_addr = edma_read_tcdreg(fsl_chan, saddr); 372 - else 373 - cur_addr = edma_read_tcdreg(fsl_chan, daddr); 370 + /* 64bit read is not atomic, need read retry when high 32bit changed */ 371 + do { 372 + if (dir == DMA_MEM_TO_DEV) { 373 + old_addr = edma_read_tcdreg(fsl_chan, saddr); 374 + cur_addr = edma_read_tcdreg(fsl_chan, saddr); 375 + } else { 376 + old_addr = edma_read_tcdreg(fsl_chan, daddr); 377 + cur_addr = edma_read_tcdreg(fsl_chan, daddr); 378 + } 379 + } while (upper_32_bits(cur_addr) != upper_32_bits(old_addr)); 374 380 375 381 /* figure out the finished and calculate the residue */ 376 382 for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { ··· 432 426 return fsl_chan->status; 433 427 } 434 428 435 - static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, 436 - struct fsl_edma_hw_tcd *tcd) 429 + static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, void *tcd) 437 430 { 438 431 u16 csr = 0; 439 432 ··· 483 478 484 479 static inline 485 480 void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan, 486 - struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, 487 - u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer, 488 - u16 biter, u16 doff, u32 dlast_sga, bool major_int, 481 + struct fsl_edma_hw_tcd *tcd, dma_addr_t src, dma_addr_t dst, 482 + u16 attr, u16 soff, u32 nbytes, dma_addr_t slast, u16 citer, 483 + u16 biter, u16 doff, dma_addr_t dlast_sga, bool major_int, 489 484 bool disable_req, bool enable_sg) 490 485 { 491 486 struct dma_slave_config *cfg = &fsl_chan->cfg; ··· 586 581 dma_addr_t dma_buf_next; 587 582 bool major_int = true; 588 583 int sg_len, i; 589 - u32 src_addr, dst_addr, last_sg, nbytes; 584 + dma_addr_t src_addr, dst_addr, last_sg; 590 585 u16 soff, doff, iter; 586 + u32 nbytes; 591 587 592 588 if (!is_slave_direction(direction)) 593 589 return NULL; ··· 660 654 struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); 661 655 struct fsl_edma_desc *fsl_desc; 662 656 struct scatterlist *sg; 663 - u32 src_addr, dst_addr, last_sg, nbytes; 657 + dma_addr_t src_addr, dst_addr, last_sg; 664 658 u16 soff, doff, iter; 659 + u32 nbytes; 665 660 int i; 666 661 667 662 if (!is_slave_direction(direction)) ··· 811 804 struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); 812 805 813 806 fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, 814 - sizeof(struct fsl_edma_hw_tcd), 807 + fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ? 808 + sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd), 815 809 32, 0); 816 810 return 0; 817 811 }
+133 -28
drivers/dma/fsl-edma-common.h
··· 87 87 __le16 biter; 88 88 }; 89 89 90 + struct fsl_edma_hw_tcd64 { 91 + __le64 saddr; 92 + __le16 soff; 93 + __le16 attr; 94 + __le32 nbytes; 95 + __le64 slast; 96 + __le64 daddr; 97 + __le64 dlast_sga; 98 + __le16 doff; 99 + __le16 citer; 100 + __le16 csr; 101 + __le16 biter; 102 + } __packed; 103 + 90 104 struct fsl_edma3_ch_reg { 91 105 __le32 ch_csr; 92 106 __le32 ch_es; ··· 110 96 __le32 ch_mux; 111 97 __le32 ch_mattr; /* edma4, reserved for edma3 */ 112 98 __le32 ch_reserved; 113 - struct fsl_edma_hw_tcd tcd; 99 + union { 100 + struct fsl_edma_hw_tcd tcd; 101 + struct fsl_edma_hw_tcd64 tcd64; 102 + }; 114 103 } __packed; 115 104 116 105 /* ··· 142 125 143 126 struct fsl_edma_sw_tcd { 144 127 dma_addr_t ptcd; 145 - struct fsl_edma_hw_tcd *vtcd; 128 + void *vtcd; 146 129 }; 147 130 148 131 struct fsl_edma_chan { ··· 161 144 u32 dma_dev_size; 162 145 enum dma_data_direction dma_dir; 163 146 char chan_name[32]; 164 - struct fsl_edma_hw_tcd __iomem *tcd; 147 + void __iomem *tcd; 165 148 void __iomem *mux_addr; 166 149 u32 real_count; 167 150 struct work_struct issue_worker; ··· 205 188 #define FSL_EDMA_DRV_CLEAR_DONE_E_SG BIT(13) 206 189 /* Need clean CHn_CSR DONE before enable TCD's MAJORELINK */ 207 190 #define FSL_EDMA_DRV_CLEAR_DONE_E_LINK BIT(14) 191 + #define FSL_EDMA_DRV_TCD64 BIT(15) 208 192 209 193 #define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \ 210 194 FSL_EDMA_DRV_BUS_8BYTE | \ ··· 249 231 struct fsl_edma_chan chans[] __counted_by(n_chans); 250 232 }; 251 233 252 - #define edma_read_tcdreg(chan, __name) \ 253 - (sizeof(chan->tcd->__name) == sizeof(u32) ? \ 254 - edma_readl(chan->edma, &chan->tcd->__name) : \ 255 - edma_readw(chan->edma, &chan->tcd->__name)) 234 + #define edma_read_tcdreg_c(chan, _tcd, __name) \ 235 + (sizeof((_tcd)->__name) == sizeof(u64) ? \ 236 + edma_readq(chan->edma, &(_tcd)->__name) : \ 237 + ((sizeof((_tcd)->__name) == sizeof(u32)) ? \ 238 + edma_readl(chan->edma, &(_tcd)->__name) : \ 239 + edma_readw(chan->edma, &(_tcd)->__name) \ 240 + )) 256 241 257 - #define edma_write_tcdreg(chan, val, __name) \ 258 - (sizeof(chan->tcd->__name) == sizeof(u32) ? \ 259 - edma_writel(chan->edma, (u32 __force)val, &chan->tcd->__name) : \ 260 - edma_writew(chan->edma, (u16 __force)val, &chan->tcd->__name)) 242 + #define edma_read_tcdreg(chan, __name) \ 243 + ((fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) ? \ 244 + edma_read_tcdreg_c(chan, ((struct fsl_edma_hw_tcd64 __iomem *)chan->tcd), __name) : \ 245 + edma_read_tcdreg_c(chan, ((struct fsl_edma_hw_tcd __iomem *)chan->tcd), __name) \ 246 + ) 261 247 262 - #define edma_cp_tcd_to_reg(chan, __tcd, __name) \ 263 - edma_write_tcdreg(chan, __tcd->__name, __name) 248 + #define edma_write_tcdreg_c(chan, _tcd, _val, __name) \ 249 + do { \ 250 + switch (sizeof(_tcd->__name)) { \ 251 + case sizeof(u64): \ 252 + edma_writeq(chan->edma, (u64 __force)_val, &_tcd->__name); \ 253 + break; \ 254 + case sizeof(u32): \ 255 + edma_writel(chan->edma, (u32 __force)_val, &_tcd->__name); \ 256 + break; \ 257 + case sizeof(u16): \ 258 + edma_writew(chan->edma, (u16 __force)_val, &_tcd->__name); \ 259 + break; \ 260 + case sizeof(u8): \ 261 + edma_writeb(chan->edma, (u8 __force)_val, &_tcd->__name); \ 262 + break; \ 263 + } \ 264 + } while (0) 265 + 266 + #define edma_write_tcdreg(chan, val, __name) \ 267 + do { \ 268 + struct fsl_edma_hw_tcd64 __iomem *tcd64_r = (struct fsl_edma_hw_tcd64 __iomem *)chan->tcd; \ 269 + struct fsl_edma_hw_tcd __iomem *tcd_r = (struct fsl_edma_hw_tcd __iomem *)chan->tcd; \ 270 + \ 271 + if (fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) \ 272 + edma_write_tcdreg_c(chan, tcd64_r, val, __name); \ 273 + else \ 274 + edma_write_tcdreg_c(chan, tcd_r, val, __name); \ 275 + } while (0) 276 + 277 + #define edma_cp_tcd_to_reg(chan, __tcd, __name) \ 278 + do { \ 279 + struct fsl_edma_hw_tcd64 __iomem *tcd64_r = (struct fsl_edma_hw_tcd64 __iomem *)chan->tcd; \ 280 + struct fsl_edma_hw_tcd __iomem *tcd_r = (struct fsl_edma_hw_tcd __iomem *)chan->tcd; \ 281 + struct fsl_edma_hw_tcd64 *tcd64_m = (struct fsl_edma_hw_tcd64 *)__tcd; \ 282 + struct fsl_edma_hw_tcd *tcd_m = (struct fsl_edma_hw_tcd *)__tcd; \ 283 + \ 284 + if (fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) \ 285 + edma_write_tcdreg_c(chan, tcd64_r, tcd64_m->__name, __name); \ 286 + else \ 287 + edma_write_tcdreg_c(chan, tcd_r, tcd_m->__name, __name); \ 288 + } while (0) 264 289 265 290 #define edma_readl_chreg(chan, __name) \ 266 291 edma_readl(chan->edma, \ ··· 315 254 (void __iomem *)&(container_of(((__force void *)chan->tcd),\ 316 255 struct fsl_edma3_ch_reg, tcd)->__name)) 317 256 318 - #define fsl_edma_get_tcd(_chan, _tcd, _field) ((_tcd)->_field) 257 + #define fsl_edma_get_tcd(_chan, _tcd, _field) \ 258 + (fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64 ? (((struct fsl_edma_hw_tcd64 *)_tcd)->_field) : \ 259 + (((struct fsl_edma_hw_tcd *)_tcd)->_field)) 319 260 320 - #define fsl_edma_le_to_cpu(x) \ 321 - (sizeof(x) == sizeof(u32) ? le32_to_cpu((__force __le32)(x)) : le16_to_cpu((__force __le16)(x))) 261 + #define fsl_edma_le_to_cpu(x) \ 262 + (sizeof(x) == sizeof(u64) ? le64_to_cpu((__force __le64)(x)) : \ 263 + (sizeof(x) == sizeof(u32) ? le32_to_cpu((__force __le32)(x)) : \ 264 + le16_to_cpu((__force __le16)(x)))) 322 265 323 - #define fsl_edma_get_tcd_to_cpu(_chan, _tcd, _field) \ 324 - fsl_edma_le_to_cpu(fsl_edma_get_tcd(_chan, _tcd, _field)) 266 + #define fsl_edma_get_tcd_to_cpu(_chan, _tcd, _field) \ 267 + (fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64 ? \ 268 + fsl_edma_le_to_cpu(((struct fsl_edma_hw_tcd64 *)_tcd)->_field) : \ 269 + fsl_edma_le_to_cpu(((struct fsl_edma_hw_tcd *)_tcd)->_field)) 325 270 326 - #define fsl_edma_set_tcd_to_le(_fsl_chan, _tcd, _val, _field) \ 327 - do { \ 328 - switch (sizeof((_tcd)->_field)) { \ 329 - case sizeof(u32): \ 330 - *(__force __le32 *)(&((_tcd)->_field)) = cpu_to_le32(_val); \ 331 - break; \ 332 - case sizeof(u16): \ 333 - *(__force __le16 *)(&((_tcd)->_field)) = cpu_to_le16(_val); \ 334 - break; \ 335 - } \ 271 + #define fsl_edma_set_tcd_to_le_c(_tcd, _val, _field) \ 272 + do { \ 273 + switch (sizeof((_tcd)->_field)) { \ 274 + case sizeof(u64): \ 275 + *(__force __le64 *)(&((_tcd)->_field)) = cpu_to_le64(_val); \ 276 + break; \ 277 + case sizeof(u32): \ 278 + *(__force __le32 *)(&((_tcd)->_field)) = cpu_to_le32(_val); \ 279 + break; \ 280 + case sizeof(u16): \ 281 + *(__force __le16 *)(&((_tcd)->_field)) = cpu_to_le16(_val); \ 282 + break; \ 283 + } \ 284 + } while (0) 285 + 286 + #define fsl_edma_set_tcd_to_le(_chan, _tcd, _val, _field) \ 287 + do { \ 288 + if (fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64) \ 289 + fsl_edma_set_tcd_to_le_c((struct fsl_edma_hw_tcd64 *)_tcd, _val, _field); \ 290 + else \ 291 + fsl_edma_set_tcd_to_le_c((struct fsl_edma_hw_tcd *)_tcd, _val, _field); \ 336 292 } while (0) 337 293 338 294 /* ··· 358 280 * For the big-endian IP module, the offset for 8-bit or 16-bit registers 359 281 * should also be swapped opposite to that in little-endian IP. 360 282 */ 283 + static inline u64 edma_readq(struct fsl_edma_engine *edma, void __iomem *addr) 284 + { 285 + u64 l, h; 286 + 287 + if (edma->big_endian) { 288 + l = ioread32be(addr); 289 + h = ioread32be(addr + 4); 290 + } else { 291 + l = ioread32(addr); 292 + h = ioread32(addr + 4); 293 + } 294 + 295 + return (h << 32) | l; 296 + } 297 + 361 298 static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) 362 299 { 363 300 if (edma->big_endian) ··· 416 323 iowrite32be(val, addr); 417 324 else 418 325 iowrite32(val, addr); 326 + } 327 + 328 + static inline void edma_writeq(struct fsl_edma_engine *edma, 329 + u64 val, void __iomem *addr) 330 + { 331 + if (edma->big_endian) { 332 + iowrite32be(val & 0xFFFFFFFF, addr); 333 + iowrite32be(val >> 32, addr + 4); 334 + } else { 335 + iowrite32(val & 0xFFFFFFFF, addr); 336 + iowrite32(val >> 32, addr + 4); 337 + } 419 338 } 420 339 421 340 static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
+14
drivers/dma/fsl-edma-main.c
··· 364 364 .setup_irq = fsl_edma3_irq_init, 365 365 }; 366 366 367 + static struct fsl_edma_drvdata imx95_data5 = { 368 + .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA4 | 369 + FSL_EDMA_DRV_TCD64, 370 + .chreg_space_sz = 0x8000, 371 + .chreg_off = 0x10000, 372 + .mux_off = 0x200, 373 + .mux_skip = sizeof(u32), 374 + .setup_irq = fsl_edma3_irq_init, 375 + }; 376 + 367 377 static const struct of_device_id fsl_edma_dt_ids[] = { 368 378 { .compatible = "fsl,vf610-edma", .data = &vf610_data}, 369 379 { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data}, ··· 382 372 { .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data}, 383 373 { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, 384 374 { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, 375 + { .compatible = "fsl,imx95-edma5", .data = &imx95_data5}, 385 376 { /* sentinel */ } 386 377 }; 387 378 MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); ··· 522 511 if (ret) 523 512 return ret; 524 513 } 514 + 515 + if (drvdata->flags & FSL_EDMA_DRV_TCD64) 516 + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 525 517 526 518 INIT_LIST_HEAD(&fsl_edma->dma_dev.channels); 527 519 for (i = 0; i < fsl_edma->n_chans; i++) {