Skip to content

Commit de7d9cb

Browse files
nxpfranklivinodkoul
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent b7b8715 commit de7d9cb

File tree

3 files changed

+170
-43
lines changed

3 files changed

+170
-43
lines changed

drivers/dma/fsl-edma-common.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
351351
{
352352
struct fsl_edma_desc *edesc = fsl_chan->edesc;
353353
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;
355355
size_t len, size;
356356
u32 nbytes = 0;
357357
int i;
@@ -367,10 +367,16 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
367367
if (!in_progress)
368368
return len;
369369

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));
374380

375381
/* figure out the finished and calculate the residue */
376382
for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
@@ -426,8 +432,7 @@ enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
426432
return fsl_chan->status;
427433
}
428434

429-
static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
430-
struct fsl_edma_hw_tcd *tcd)
435+
static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, void *tcd)
431436
{
432437
u16 csr = 0;
433438

@@ -478,9 +483,9 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
478483

479484
static inline
480485
void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
481-
struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
482-
u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
483-
u16 biter, u16 doff, u32 dlast_sga, bool major_int,
486+
struct fsl_edma_hw_tcd *tcd, dma_addr_t src, dma_addr_t dst,
487+
u16 attr, u16 soff, u32 nbytes, dma_addr_t slast, u16 citer,
488+
u16 biter, u16 doff, dma_addr_t dlast_sga, bool major_int,
484489
bool disable_req, bool enable_sg)
485490
{
486491
struct dma_slave_config *cfg = &fsl_chan->cfg;
@@ -581,8 +586,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
581586
dma_addr_t dma_buf_next;
582587
bool major_int = true;
583588
int sg_len, i;
584-
u32 src_addr, dst_addr, last_sg, nbytes;
589+
dma_addr_t src_addr, dst_addr, last_sg;
585590
u16 soff, doff, iter;
591+
u32 nbytes;
586592

587593
if (!is_slave_direction(direction))
588594
return NULL;
@@ -654,8 +660,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
654660
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
655661
struct fsl_edma_desc *fsl_desc;
656662
struct scatterlist *sg;
657-
u32 src_addr, dst_addr, last_sg, nbytes;
663+
dma_addr_t src_addr, dst_addr, last_sg;
658664
u16 soff, doff, iter;
665+
u32 nbytes;
659666
int i;
660667

661668
if (!is_slave_direction(direction))
@@ -804,7 +811,8 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
804811
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
805812

806813
fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
807-
sizeof(struct fsl_edma_hw_tcd),
814+
fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
815+
sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd),
808816
32, 0);
809817
return 0;
810818
}

drivers/dma/fsl-edma-common.h

Lines changed: 135 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ struct fsl_edma_hw_tcd {
8787
__le16 biter;
8888
};
8989

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+
90104
struct fsl_edma3_ch_reg {
91105
__le32 ch_csr;
92106
__le32 ch_es;
@@ -96,7 +110,10 @@ struct fsl_edma3_ch_reg {
96110
__le32 ch_mux;
97111
__le32 ch_mattr; /* edma4, reserved for edma3 */
98112
__le32 ch_reserved;
99-
struct fsl_edma_hw_tcd tcd;
113+
union {
114+
struct fsl_edma_hw_tcd tcd;
115+
struct fsl_edma_hw_tcd64 tcd64;
116+
};
100117
} __packed;
101118

102119
/*
@@ -125,7 +142,7 @@ struct edma_regs {
125142

126143
struct fsl_edma_sw_tcd {
127144
dma_addr_t ptcd;
128-
struct fsl_edma_hw_tcd *vtcd;
145+
void *vtcd;
129146
};
130147

131148
struct fsl_edma_chan {
@@ -144,7 +161,7 @@ struct fsl_edma_chan {
144161
u32 dma_dev_size;
145162
enum dma_data_direction dma_dir;
146163
char chan_name[32];
147-
struct fsl_edma_hw_tcd __iomem *tcd;
164+
void __iomem *tcd;
148165
void __iomem *mux_addr;
149166
u32 real_count;
150167
struct work_struct issue_worker;
@@ -188,6 +205,7 @@ struct fsl_edma_desc {
188205
#define FSL_EDMA_DRV_CLEAR_DONE_E_SG BIT(13)
189206
/* Need clean CHn_CSR DONE before enable TCD's MAJORELINK */
190207
#define FSL_EDMA_DRV_CLEAR_DONE_E_LINK BIT(14)
208+
#define FSL_EDMA_DRV_TCD64 BIT(15)
191209

192210
#define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
193211
FSL_EDMA_DRV_BUS_8BYTE | \
@@ -231,18 +249,61 @@ struct fsl_edma_engine {
231249
struct fsl_edma_chan chans[] __counted_by(n_chans);
232250
};
233251

234-
#define edma_read_tcdreg(chan, __name) \
235-
(sizeof(chan->tcd->__name) == sizeof(u32) ? \
236-
edma_readl(chan->edma, &chan->tcd->__name) : \
237-
edma_readw(chan->edma, &chan->tcd->__name))
252+
#define edma_read_tcdreg_c(chan, _tcd, __name) \
253+
(sizeof((_tcd)->__name) == sizeof(u64) ? \
254+
edma_readq(chan->edma, &(_tcd)->__name) : \
255+
((sizeof((_tcd)->__name) == sizeof(u32)) ? \
256+
edma_readl(chan->edma, &(_tcd)->__name) : \
257+
edma_readw(chan->edma, &(_tcd)->__name) \
258+
))
259+
260+
#define edma_read_tcdreg(chan, __name) \
261+
((fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) ? \
262+
edma_read_tcdreg_c(chan, ((struct fsl_edma_hw_tcd64 __iomem *)chan->tcd), __name) : \
263+
edma_read_tcdreg_c(chan, ((struct fsl_edma_hw_tcd __iomem *)chan->tcd), __name) \
264+
)
265+
266+
#define edma_write_tcdreg_c(chan, _tcd, _val, __name) \
267+
do { \
268+
switch (sizeof(_tcd->__name)) { \
269+
case sizeof(u64): \
270+
edma_writeq(chan->edma, (u64 __force)_val, &_tcd->__name); \
271+
break; \
272+
case sizeof(u32): \
273+
edma_writel(chan->edma, (u32 __force)_val, &_tcd->__name); \
274+
break; \
275+
case sizeof(u16): \
276+
edma_writew(chan->edma, (u16 __force)_val, &_tcd->__name); \
277+
break; \
278+
case sizeof(u8): \
279+
edma_writeb(chan->edma, (u8 __force)_val, &_tcd->__name); \
280+
break; \
281+
} \
282+
} while (0)
238283

239-
#define edma_write_tcdreg(chan, val, __name) \
240-
(sizeof(chan->tcd->__name) == sizeof(u32) ? \
241-
edma_writel(chan->edma, (u32 __force)val, &chan->tcd->__name) : \
242-
edma_writew(chan->edma, (u16 __force)val, &chan->tcd->__name))
284+
#define edma_write_tcdreg(chan, val, __name) \
285+
do { \
286+
struct fsl_edma_hw_tcd64 __iomem *tcd64_r = (struct fsl_edma_hw_tcd64 __iomem *)chan->tcd; \
287+
struct fsl_edma_hw_tcd __iomem *tcd_r = (struct fsl_edma_hw_tcd __iomem *)chan->tcd; \
288+
\
289+
if (fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) \
290+
edma_write_tcdreg_c(chan, tcd64_r, val, __name); \
291+
else \
292+
edma_write_tcdreg_c(chan, tcd_r, val, __name); \
293+
} while (0)
243294

244-
#define edma_cp_tcd_to_reg(chan, __tcd, __name) \
245-
edma_write_tcdreg(chan, __tcd->__name, __name)
295+
#define edma_cp_tcd_to_reg(chan, __tcd, __name) \
296+
do { \
297+
struct fsl_edma_hw_tcd64 __iomem *tcd64_r = (struct fsl_edma_hw_tcd64 __iomem *)chan->tcd; \
298+
struct fsl_edma_hw_tcd __iomem *tcd_r = (struct fsl_edma_hw_tcd __iomem *)chan->tcd; \
299+
struct fsl_edma_hw_tcd64 *tcd64_m = (struct fsl_edma_hw_tcd64 *)__tcd; \
300+
struct fsl_edma_hw_tcd *tcd_m = (struct fsl_edma_hw_tcd *)__tcd; \
301+
\
302+
if (fsl_edma_drvflags(chan) & FSL_EDMA_DRV_TCD64) \
303+
edma_write_tcdreg_c(chan, tcd64_r, tcd64_m->__name, __name); \
304+
else \
305+
edma_write_tcdreg_c(chan, tcd_r, tcd_m->__name, __name); \
306+
} while (0)
246307

247308
#define edma_readl_chreg(chan, __name) \
248309
edma_readl(chan->edma, \
@@ -254,24 +315,41 @@ struct fsl_edma_engine {
254315
(void __iomem *)&(container_of(((__force void *)chan->tcd),\
255316
struct fsl_edma3_ch_reg, tcd)->__name))
256317

257-
#define fsl_edma_get_tcd(_chan, _tcd, _field) ((_tcd)->_field)
258-
259-
#define fsl_edma_le_to_cpu(x) \
260-
(sizeof(x) == sizeof(u32) ? le32_to_cpu((__force __le32)(x)) : le16_to_cpu((__force __le16)(x)))
261-
262-
#define fsl_edma_get_tcd_to_cpu(_chan, _tcd, _field) \
263-
fsl_edma_le_to_cpu(fsl_edma_get_tcd(_chan, _tcd, _field))
318+
#define fsl_edma_get_tcd(_chan, _tcd, _field) \
319+
(fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64 ? (((struct fsl_edma_hw_tcd64 *)_tcd)->_field) : \
320+
(((struct fsl_edma_hw_tcd *)_tcd)->_field))
321+
322+
#define fsl_edma_le_to_cpu(x) \
323+
(sizeof(x) == sizeof(u64) ? le64_to_cpu((__force __le64)(x)) : \
324+
(sizeof(x) == sizeof(u32) ? le32_to_cpu((__force __le32)(x)) : \
325+
le16_to_cpu((__force __le16)(x))))
326+
327+
#define fsl_edma_get_tcd_to_cpu(_chan, _tcd, _field) \
328+
(fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64 ? \
329+
fsl_edma_le_to_cpu(((struct fsl_edma_hw_tcd64 *)_tcd)->_field) : \
330+
fsl_edma_le_to_cpu(((struct fsl_edma_hw_tcd *)_tcd)->_field))
331+
332+
#define fsl_edma_set_tcd_to_le_c(_tcd, _val, _field) \
333+
do { \
334+
switch (sizeof((_tcd)->_field)) { \
335+
case sizeof(u64): \
336+
*(__force __le64 *)(&((_tcd)->_field)) = cpu_to_le64(_val); \
337+
break; \
338+
case sizeof(u32): \
339+
*(__force __le32 *)(&((_tcd)->_field)) = cpu_to_le32(_val); \
340+
break; \
341+
case sizeof(u16): \
342+
*(__force __le16 *)(&((_tcd)->_field)) = cpu_to_le16(_val); \
343+
break; \
344+
} \
345+
} while (0)
264346

265-
#define fsl_edma_set_tcd_to_le(_fsl_chan, _tcd, _val, _field) \
266-
do { \
267-
switch (sizeof((_tcd)->_field)) { \
268-
case sizeof(u32): \
269-
*(__force __le32 *)(&((_tcd)->_field)) = cpu_to_le32(_val); \
270-
break; \
271-
case sizeof(u16): \
272-
*(__force __le16 *)(&((_tcd)->_field)) = cpu_to_le16(_val); \
273-
break; \
274-
} \
347+
#define fsl_edma_set_tcd_to_le(_chan, _tcd, _val, _field) \
348+
do { \
349+
if (fsl_edma_drvflags(_chan) & FSL_EDMA_DRV_TCD64) \
350+
fsl_edma_set_tcd_to_le_c((struct fsl_edma_hw_tcd64 *)_tcd, _val, _field); \
351+
else \
352+
fsl_edma_set_tcd_to_le_c((struct fsl_edma_hw_tcd *)_tcd, _val, _field); \
275353
} while (0)
276354

277355
/*
@@ -280,6 +358,21 @@ do { \
280358
* For the big-endian IP module, the offset for 8-bit or 16-bit registers
281359
* should also be swapped opposite to that in little-endian IP.
282360
*/
361+
static inline u64 edma_readq(struct fsl_edma_engine *edma, void __iomem *addr)
362+
{
363+
u64 l, h;
364+
365+
if (edma->big_endian) {
366+
l = ioread32be(addr);
367+
h = ioread32be(addr + 4);
368+
} else {
369+
l = ioread32(addr);
370+
h = ioread32(addr + 4);
371+
}
372+
373+
return (h << 32) | l;
374+
}
375+
283376
static inline u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
284377
{
285378
if (edma->big_endian)
@@ -325,6 +418,18 @@ static inline void edma_writel(struct fsl_edma_engine *edma,
325418
iowrite32(val, addr);
326419
}
327420

421+
static inline void edma_writeq(struct fsl_edma_engine *edma,
422+
u64 val, void __iomem *addr)
423+
{
424+
if (edma->big_endian) {
425+
iowrite32be(val & 0xFFFFFFFF, addr);
426+
iowrite32be(val >> 32, addr + 4);
427+
} else {
428+
iowrite32(val & 0xFFFFFFFF, addr);
429+
iowrite32(val >> 32, addr + 4);
430+
}
431+
}
432+
328433
static inline struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
329434
{
330435
return container_of(chan, struct fsl_edma_chan, vchan.chan);

drivers/dma/fsl-edma-main.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,16 @@ static struct fsl_edma_drvdata imx93_data4 = {
364364
.setup_irq = fsl_edma3_irq_init,
365365
};
366366

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+
367377
static const struct of_device_id fsl_edma_dt_ids[] = {
368378
{ .compatible = "fsl,vf610-edma", .data = &vf610_data},
369379
{ .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data},
@@ -372,6 +382,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = {
372382
{ .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data},
373383
{ .compatible = "fsl,imx93-edma3", .data = &imx93_data3},
374384
{ .compatible = "fsl,imx93-edma4", .data = &imx93_data4},
385+
{ .compatible = "fsl,imx95-edma5", .data = &imx95_data5},
375386
{ /* sentinel */ }
376387
};
377388
MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
@@ -512,6 +523,9 @@ static int fsl_edma_probe(struct platform_device *pdev)
512523
return ret;
513524
}
514525

526+
if (drvdata->flags & FSL_EDMA_DRV_TCD64)
527+
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
528+
515529
INIT_LIST_HEAD(&fsl_edma->dma_dev.channels);
516530
for (i = 0; i < fsl_edma->n_chans; i++) {
517531
struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i];

0 commit comments

Comments
 (0)