dmaengine: fsl-edma: integrate TCD64 support for i.MX95
[linux-2.6-microblaze.git] / drivers / dma / fsl-edma-common.c
index 65f466a..c8acff0 100644 (file)
@@ -351,7 +351,7 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
 {
        struct fsl_edma_desc *edesc = fsl_chan->edesc;
        enum dma_transfer_direction dir = edesc->dirn;
-       dma_addr_t cur_addr, dma_addr;
+       dma_addr_t cur_addr, dma_addr, old_addr;
        size_t len, size;
        u32 nbytes = 0;
        int i;
@@ -367,10 +367,16 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
        if (!in_progress)
                return len;
 
-       if (dir == DMA_MEM_TO_DEV)
-               cur_addr = edma_read_tcdreg(fsl_chan, saddr);
-       else
-               cur_addr = edma_read_tcdreg(fsl_chan, daddr);
+       /* 64bit read is not atomic, need read retry when high 32bit changed */
+       do {
+               if (dir == DMA_MEM_TO_DEV) {
+                       old_addr = edma_read_tcdreg(fsl_chan, saddr);
+                       cur_addr = edma_read_tcdreg(fsl_chan, saddr);
+               } else {
+                       old_addr = edma_read_tcdreg(fsl_chan, daddr);
+                       cur_addr = edma_read_tcdreg(fsl_chan, daddr);
+               }
+       } while (upper_32_bits(cur_addr) != upper_32_bits(old_addr));
 
        /* figure out the finished and calculate the residue */
        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,
        return fsl_chan->status;
 }
 
-static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
-                                 struct fsl_edma_hw_tcd *tcd)
+static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, void *tcd)
 {
        u16 csr = 0;
 
@@ -478,9 +483,9 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
 
 static inline
 void fsl_edma_fill_tcd(struct fsl_edma_chan *fsl_chan,
-                      struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
-                      u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
-                      u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+                      struct fsl_edma_hw_tcd *tcd, dma_addr_t src, dma_addr_t dst,
+                      u16 attr, u16 soff, u32 nbytes, dma_addr_t slast, u16 citer,
+                      u16 biter, u16 doff, dma_addr_t dlast_sga, bool major_int,
                       bool disable_req, bool enable_sg)
 {
        struct dma_slave_config *cfg = &fsl_chan->cfg;
@@ -581,8 +586,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
        dma_addr_t dma_buf_next;
        bool major_int = true;
        int sg_len, i;
-       u32 src_addr, dst_addr, last_sg, nbytes;
+       dma_addr_t src_addr, dst_addr, last_sg;
        u16 soff, doff, iter;
+       u32 nbytes;
 
        if (!is_slave_direction(direction))
                return NULL;
@@ -654,8 +660,9 @@ struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
        struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
        struct fsl_edma_desc *fsl_desc;
        struct scatterlist *sg;
-       u32 src_addr, dst_addr, last_sg, nbytes;
+       dma_addr_t src_addr, dst_addr, last_sg;
        u16 soff, doff, iter;
+       u32 nbytes;
        int i;
 
        if (!is_slave_direction(direction))
@@ -804,7 +811,8 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
        struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
 
        fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
-                               sizeof(struct fsl_edma_hw_tcd),
+                               fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
+                               sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd),
                                32, 0);
        return 0;
 }