int directed;
        void *token;
        void *data;
+       int flags;
        int len;
 };
 
                                 (directed << CPDMA_TO_PORT_SHIFT));    \
        } while (0)
 
+#define CPDMA_DMA_EXT_MAP              BIT(16)
+
 static void cpdma_desc_pool_destroy(struct cpdma_ctlr *ctlr)
 {
        struct cpdma_desc_pool *pool = ctlr->pool;
        struct cpdma_chan               *chan = si->chan;
        struct cpdma_ctlr               *ctlr = chan->ctlr;
        int                             len = si->len;
+       int                             swlen = len;
        struct cpdma_desc __iomem       *desc;
        dma_addr_t                      buffer;
        u32                             mode;
                chan->stats.runt_transmit_buff++;
        }
 
-       buffer = dma_map_single(ctlr->dev, si->data, len, chan->dir);
-       ret = dma_mapping_error(ctlr->dev, buffer);
-       if (ret) {
-               cpdma_desc_free(ctlr->pool, desc, 1);
-               return -EINVAL;
-       }
-
        mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
        cpdma_desc_to_port(chan, mode, si->directed);
 
+       if (si->flags & CPDMA_DMA_EXT_MAP) {
+               buffer = (dma_addr_t)si->data;
+               dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir);
+               swlen |= CPDMA_DMA_EXT_MAP;
+       } else {
+               buffer = dma_map_single(ctlr->dev, si->data, len, chan->dir);
+               ret = dma_mapping_error(ctlr->dev, buffer);
+               if (ret) {
+                       cpdma_desc_free(ctlr->pool, desc, 1);
+                       return -EINVAL;
+               }
+       }
+
        /* Relaxed IO accessors can be used here as there is read barrier
         * at the end of write sequence.
         */
        writel_relaxed(mode | len, &desc->hw_mode);
        writel_relaxed((uintptr_t)si->token, &desc->sw_token);
        writel_relaxed(buffer, &desc->sw_buffer);
-       writel_relaxed(len, &desc->sw_len);
+       writel_relaxed(swlen, &desc->sw_len);
        desc_read(desc, sw_len);
 
        __cpdma_chan_submit(chan, desc);
        si.data = data;
        si.len = len;
        si.directed = directed;
+       si.flags = 0;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->state == CPDMA_STATE_TEARDOWN) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return -EINVAL;
+       }
+
+       ret = cpdma_chan_submit_si(&si);
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return ret;
+}
+
+int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
+                                 dma_addr_t data, int len, int directed)
+{
+       struct submit_info si;
+       unsigned long flags;
+       int ret;
+
+       si.chan = chan;
+       si.token = token;
+       si.data = (void *)data;
+       si.len = len;
+       si.directed = directed;
+       si.flags = CPDMA_DMA_EXT_MAP;
 
        spin_lock_irqsave(&chan->lock, flags);
        if (chan->state == CPDMA_STATE_TEARDOWN) {
        si.data = data;
        si.len = len;
        si.directed = directed;
+       si.flags = 0;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       if (chan->state != CPDMA_STATE_ACTIVE) {
+               spin_unlock_irqrestore(&chan->lock, flags);
+               return -EINVAL;
+       }
+
+       ret = cpdma_chan_submit_si(&si);
+       spin_unlock_irqrestore(&chan->lock, flags);
+       return ret;
+}
+
+int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
+                            dma_addr_t data, int len, int directed)
+{
+       struct submit_info si;
+       unsigned long flags;
+       int ret;
+
+       si.chan = chan;
+       si.token = token;
+       si.data = (void *)data;
+       si.len = len;
+       si.directed = directed;
+       si.flags = CPDMA_DMA_EXT_MAP;
 
        spin_lock_irqsave(&chan->lock, flags);
        if (chan->state != CPDMA_STATE_ACTIVE) {
        uintptr_t                       token;
 
        token      = desc_read(desc, sw_token);
-       buff_dma   = desc_read(desc, sw_buffer);
        origlen    = desc_read(desc, sw_len);
 
-       dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+       buff_dma   = desc_read(desc, sw_buffer);
+       if (origlen & CPDMA_DMA_EXT_MAP) {
+               origlen &= ~CPDMA_DMA_EXT_MAP;
+               dma_sync_single_for_cpu(ctlr->dev, buff_dma, origlen,
+                                       chan->dir);
+       } else {
+               dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+       }
+
        cpdma_desc_free(pool, desc, 1);
        (*chan->handler)((void *)token, outlen, status);
 }