Loading drivers/dma/edma.c +3 −0 Original line number Diff line number Diff line Loading @@ -2450,6 +2450,9 @@ static int edma_pm_resume(struct device *dev) int i; s8 (*queue_priority_mapping)[2]; /* re initialize dummy slot to dummy param set */ edma_write_slot(ecc, ecc->dummy_slot, &dummy_paramset); queue_priority_mapping = ecc->info->queue_priority_mapping; /* Event queue priority mapping */ Loading drivers/dma/omap-dma.c +150 −37 Original line number Diff line number Diff line Loading @@ -166,6 +166,9 @@ enum { CSDP_DST_BURST_16 = 1 << 14, CSDP_DST_BURST_32 = 2 << 14, CSDP_DST_BURST_64 = 3 << 14, CSDP_WRITE_NON_POSTED = 0 << 16, CSDP_WRITE_POSTED = 1 << 16, CSDP_WRITE_LAST_NON_POSTED = 2 << 16, CICR_TOUT_IE = BIT(0), /* OMAP1 only */ CICR_DROP_IE = BIT(1), Loading Loading @@ -422,7 +425,30 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) c->running = true; } static void omap_dma_stop(struct omap_chan *c) static void omap_dma_drain_chan(struct omap_chan *c) { int i; u32 val; /* Wait for sDMA FIFO to drain */ for (i = 0; ; i++) { val = omap_dma_chan_read(c, CCR); if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))) break; if (i > 100) break; udelay(5); } if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)) dev_err(c->vc.chan.device->dev, "DMA drain did not complete on lch %d\n", c->dma_ch); } static int omap_dma_stop(struct omap_chan *c) { struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device); uint32_t val; Loading @@ -435,7 +461,6 @@ static void omap_dma_stop(struct omap_chan *c) val = omap_dma_chan_read(c, CCR); if (od->plat->errata & DMA_ERRATA_i541 && val & CCR_TRIGGER_SRC) { uint32_t sysconfig; unsigned i; sysconfig = omap_dma_glbl_read(od, OCP_SYSCONFIG); val = sysconfig & ~DMA_SYSCONFIG_MIDLEMODE_MASK; Loading @@ -446,27 +471,19 @@ static void omap_dma_stop(struct omap_chan *c) val &= ~CCR_ENABLE; omap_dma_chan_write(c, CCR, val); /* Wait for sDMA FIFO to drain */ for (i = 0; ; i++) { val = omap_dma_chan_read(c, CCR); if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))) break; if (i > 100) break; udelay(5); } if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)) dev_err(c->vc.chan.device->dev, "DMA drain did not complete on lch %d\n", c->dma_ch); if (!(c->ccr & CCR_BUFFERING_DISABLE)) omap_dma_drain_chan(c); omap_dma_glbl_write(od, OCP_SYSCONFIG, sysconfig); } else { if (!(val & CCR_ENABLE)) return -EINVAL; val &= ~CCR_ENABLE; omap_dma_chan_write(c, CCR, val); if (!(c->ccr & CCR_BUFFERING_DISABLE)) omap_dma_drain_chan(c); } mb(); Loading @@ -481,8 +498,8 @@ static void omap_dma_stop(struct omap_chan *c) omap_dma_chan_write(c, CLNK_CTRL, val); } c->running = false; return 0; } static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d) Loading Loading @@ -836,6 +853,8 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, } else { txstate->residue = 0; } if (ret == DMA_IN_PROGRESS && c->paused) ret = DMA_PAUSED; spin_unlock_irqrestore(&c->vc.lock, flags); return ret; Loading Loading @@ -865,15 +884,18 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( unsigned i, es, en, frame_bytes; bool ll_failed = false; u32 burst; u32 port_window, port_window_bytes; if (dir == DMA_DEV_TO_MEM) { dev_addr = c->cfg.src_addr; dev_width = c->cfg.src_addr_width; burst = c->cfg.src_maxburst; port_window = c->cfg.src_port_window_size; } else if (dir == DMA_MEM_TO_DEV) { dev_addr = c->cfg.dst_addr; dev_width = c->cfg.dst_addr_width; burst = c->cfg.dst_maxburst; port_window = c->cfg.dst_port_window_size; } else { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; Loading @@ -894,6 +916,12 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( return NULL; } /* When the port_window is used, one frame must cover the window */ if (port_window) { burst = port_window; port_window_bytes = port_window * es_bytes[es]; } /* Now allocate and setup the descriptor. */ d = kzalloc(sizeof(*d) + sglen * sizeof(d->sg[0]), GFP_ATOMIC); if (!d) Loading @@ -905,11 +933,45 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr = c->ccr | CCR_SYNC_FRAME; if (dir == DMA_DEV_TO_MEM) { d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_CONSTANT; d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; d->ccr |= CCR_DST_AMODE_POSTINC; if (port_window) { d->ccr |= CCR_SRC_AMODE_DBLIDX; d->ei = 1; /* * One frame covers the port_window and by configure * the source frame index to be -1 * (port_window - 1) * we instruct the sDMA that after a frame is processed * it should move back to the start of the window. */ d->fi = -(port_window_bytes - 1); if (port_window_bytes >= 64) d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; else if (port_window_bytes >= 32) d->csdp = CSDP_SRC_BURST_32 | CSDP_SRC_PACKED; else if (port_window_bytes >= 16) d->csdp = CSDP_SRC_BURST_16 | CSDP_SRC_PACKED; } else { d->ccr |= CCR_SRC_AMODE_CONSTANT; } } else { d->ccr |= CCR_DST_AMODE_CONSTANT | CCR_SRC_AMODE_POSTINC; d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; d->ccr |= CCR_SRC_AMODE_POSTINC; if (port_window) { d->ccr |= CCR_DST_AMODE_DBLIDX; if (port_window_bytes >= 64) d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; else if (port_window_bytes >= 32) d->csdp = CSDP_DST_BURST_32 | CSDP_DST_PACKED; else if (port_window_bytes >= 16) d->csdp = CSDP_DST_BURST_16 | CSDP_DST_PACKED; } else { d->ccr |= CCR_DST_AMODE_CONSTANT; } } d->cicr = CICR_DROP_IE | CICR_BLOCK_IE; Loading @@ -927,6 +989,9 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr |= CCR_TRIGGER_SRC; d->cicr |= CICR_MISALIGNED_ERR_IE | CICR_TRANS_ERR_IE; if (port_window) d->csdp |= CSDP_WRITE_LAST_NON_POSTED; } if (od->plat->errata & DMA_ERRATA_PARALLEL_CHANNELS) d->clnk_ctrl = c->dma_ch; Loading @@ -952,6 +1017,16 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( osg->addr = sg_dma_address(sgent); osg->en = en; osg->fn = sg_dma_len(sgent) / frame_bytes; if (port_window && dir == DMA_MEM_TO_DEV) { osg->ei = 1; /* * One frame covers the port_window and by configure * the source frame index to be -1 * (port_window - 1) * we instruct the sDMA that after a frame is processed * it should move back to the start of the window. */ osg->fi = -(port_window_bytes - 1); } if (d->using_ll) { osg->t2_desc = dma_pool_alloc(od->desc_pool, GFP_ATOMIC, Loading Loading @@ -1247,10 +1322,8 @@ static int omap_dma_terminate_all(struct dma_chan *chan) omap_dma_stop(c); } if (c->cyclic) { c->cyclic = false; c->paused = false; } vchan_get_all_descriptors(&c->vc, &head); spin_unlock_irqrestore(&c->vc.lock, flags); Loading @@ -1269,28 +1342,66 @@ static void omap_dma_synchronize(struct dma_chan *chan) static int omap_dma_pause(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); struct omap_dmadev *od = to_omap_dma_dev(chan->device); unsigned long flags; int ret = -EINVAL; bool can_pause = false; /* Pause/Resume only allowed with cyclic mode */ if (!c->cyclic) return -EINVAL; spin_lock_irqsave(&od->irq_lock, flags); if (!c->paused) { omap_dma_stop(c); if (!c->desc) goto out; if (c->cyclic) can_pause = true; /* * We do not allow DMA_MEM_TO_DEV transfers to be paused. * From the AM572x TRM, 16.1.4.18 Disabling a Channel During Transfer: * "When a channel is disabled during a transfer, the channel undergoes * an abort, unless it is hardware-source-synchronized …". * A source-synchronised channel is one where the fetching of data is * under control of the device. In other words, a device-to-memory * transfer. So, a destination-synchronised channel (which would be a * memory-to-device transfer) undergoes an abort if the the CCR_ENABLE * bit is cleared. * From 16.1.4.20.4.6.2 Abort: "If an abort trigger occurs, the channel * aborts immediately after completion of current read/write * transactions and then the FIFO is cleaned up." The term "cleaned up" * is not defined. TI recommends to check that RD_ACTIVE and WR_ACTIVE * are both clear _before_ disabling the channel, otherwise data loss * will occur. * The problem is that if the channel is active, then device activity * can result in DMA activity starting between reading those as both * clear and the write to DMA_CCR to clear the enable bit hitting the * hardware. If the DMA hardware can't drain the data in its FIFO to the * destination, then data loss "might" occur (say if we write to an UART * and the UART is not accepting any further data). */ else if (c->desc->dir == DMA_DEV_TO_MEM) can_pause = true; if (can_pause && !c->paused) { ret = omap_dma_stop(c); if (!ret) c->paused = true; } out: spin_unlock_irqrestore(&od->irq_lock, flags); return 0; return ret; } static int omap_dma_resume(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); struct omap_dmadev *od = to_omap_dma_dev(chan->device); unsigned long flags; int ret = -EINVAL; /* Pause/Resume only allowed with cyclic mode */ if (!c->cyclic) return -EINVAL; spin_lock_irqsave(&od->irq_lock, flags); if (c->paused) { if (c->paused && c->desc) { mb(); /* Restore channel link register */ Loading @@ -1298,9 +1409,11 @@ static int omap_dma_resume(struct dma_chan *chan) omap_dma_start(c, c->desc); c->paused = false; ret = 0; } spin_unlock_irqrestore(&od->irq_lock, flags); return 0; return ret; } static int omap_dma_chan_init(struct omap_dmadev *od) Loading include/linux/dmaengine.h +8 −0 Original line number Diff line number Diff line Loading @@ -336,6 +336,12 @@ enum dma_slave_buswidth { * may or may not be applicable on memory sources. * @dst_maxburst: same as src_maxburst but for destination target * mutatis mutandis. * @src_port_window_size: The length of the register area in words the data need * to be accessed on the device side. It is only used for devices which is using * an area instead of a single register to receive the data. Typically the DMA * loops in this area in order to transfer the data. * @dst_port_window_size: same as src_port_window_size but for the destination * port. * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill * with 'true' if peripheral should be flow controller. Direction will be * selected at Runtime. Loading Loading @@ -363,6 +369,8 @@ struct dma_slave_config { enum dma_slave_buswidth dst_addr_width; u32 src_maxburst; u32 dst_maxburst; u32 src_port_window_size; u32 dst_port_window_size; bool device_fc; unsigned int slave_id; }; Loading Loading
drivers/dma/edma.c +3 −0 Original line number Diff line number Diff line Loading @@ -2450,6 +2450,9 @@ static int edma_pm_resume(struct device *dev) int i; s8 (*queue_priority_mapping)[2]; /* re initialize dummy slot to dummy param set */ edma_write_slot(ecc, ecc->dummy_slot, &dummy_paramset); queue_priority_mapping = ecc->info->queue_priority_mapping; /* Event queue priority mapping */ Loading
drivers/dma/omap-dma.c +150 −37 Original line number Diff line number Diff line Loading @@ -166,6 +166,9 @@ enum { CSDP_DST_BURST_16 = 1 << 14, CSDP_DST_BURST_32 = 2 << 14, CSDP_DST_BURST_64 = 3 << 14, CSDP_WRITE_NON_POSTED = 0 << 16, CSDP_WRITE_POSTED = 1 << 16, CSDP_WRITE_LAST_NON_POSTED = 2 << 16, CICR_TOUT_IE = BIT(0), /* OMAP1 only */ CICR_DROP_IE = BIT(1), Loading Loading @@ -422,7 +425,30 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) c->running = true; } static void omap_dma_stop(struct omap_chan *c) static void omap_dma_drain_chan(struct omap_chan *c) { int i; u32 val; /* Wait for sDMA FIFO to drain */ for (i = 0; ; i++) { val = omap_dma_chan_read(c, CCR); if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))) break; if (i > 100) break; udelay(5); } if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)) dev_err(c->vc.chan.device->dev, "DMA drain did not complete on lch %d\n", c->dma_ch); } static int omap_dma_stop(struct omap_chan *c) { struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device); uint32_t val; Loading @@ -435,7 +461,6 @@ static void omap_dma_stop(struct omap_chan *c) val = omap_dma_chan_read(c, CCR); if (od->plat->errata & DMA_ERRATA_i541 && val & CCR_TRIGGER_SRC) { uint32_t sysconfig; unsigned i; sysconfig = omap_dma_glbl_read(od, OCP_SYSCONFIG); val = sysconfig & ~DMA_SYSCONFIG_MIDLEMODE_MASK; Loading @@ -446,27 +471,19 @@ static void omap_dma_stop(struct omap_chan *c) val &= ~CCR_ENABLE; omap_dma_chan_write(c, CCR, val); /* Wait for sDMA FIFO to drain */ for (i = 0; ; i++) { val = omap_dma_chan_read(c, CCR); if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))) break; if (i > 100) break; udelay(5); } if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)) dev_err(c->vc.chan.device->dev, "DMA drain did not complete on lch %d\n", c->dma_ch); if (!(c->ccr & CCR_BUFFERING_DISABLE)) omap_dma_drain_chan(c); omap_dma_glbl_write(od, OCP_SYSCONFIG, sysconfig); } else { if (!(val & CCR_ENABLE)) return -EINVAL; val &= ~CCR_ENABLE; omap_dma_chan_write(c, CCR, val); if (!(c->ccr & CCR_BUFFERING_DISABLE)) omap_dma_drain_chan(c); } mb(); Loading @@ -481,8 +498,8 @@ static void omap_dma_stop(struct omap_chan *c) omap_dma_chan_write(c, CLNK_CTRL, val); } c->running = false; return 0; } static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d) Loading Loading @@ -836,6 +853,8 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, } else { txstate->residue = 0; } if (ret == DMA_IN_PROGRESS && c->paused) ret = DMA_PAUSED; spin_unlock_irqrestore(&c->vc.lock, flags); return ret; Loading Loading @@ -865,15 +884,18 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( unsigned i, es, en, frame_bytes; bool ll_failed = false; u32 burst; u32 port_window, port_window_bytes; if (dir == DMA_DEV_TO_MEM) { dev_addr = c->cfg.src_addr; dev_width = c->cfg.src_addr_width; burst = c->cfg.src_maxburst; port_window = c->cfg.src_port_window_size; } else if (dir == DMA_MEM_TO_DEV) { dev_addr = c->cfg.dst_addr; dev_width = c->cfg.dst_addr_width; burst = c->cfg.dst_maxburst; port_window = c->cfg.dst_port_window_size; } else { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; Loading @@ -894,6 +916,12 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( return NULL; } /* When the port_window is used, one frame must cover the window */ if (port_window) { burst = port_window; port_window_bytes = port_window * es_bytes[es]; } /* Now allocate and setup the descriptor. */ d = kzalloc(sizeof(*d) + sglen * sizeof(d->sg[0]), GFP_ATOMIC); if (!d) Loading @@ -905,11 +933,45 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr = c->ccr | CCR_SYNC_FRAME; if (dir == DMA_DEV_TO_MEM) { d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_CONSTANT; d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; d->ccr |= CCR_DST_AMODE_POSTINC; if (port_window) { d->ccr |= CCR_SRC_AMODE_DBLIDX; d->ei = 1; /* * One frame covers the port_window and by configure * the source frame index to be -1 * (port_window - 1) * we instruct the sDMA that after a frame is processed * it should move back to the start of the window. */ d->fi = -(port_window_bytes - 1); if (port_window_bytes >= 64) d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; else if (port_window_bytes >= 32) d->csdp = CSDP_SRC_BURST_32 | CSDP_SRC_PACKED; else if (port_window_bytes >= 16) d->csdp = CSDP_SRC_BURST_16 | CSDP_SRC_PACKED; } else { d->ccr |= CCR_SRC_AMODE_CONSTANT; } } else { d->ccr |= CCR_DST_AMODE_CONSTANT | CCR_SRC_AMODE_POSTINC; d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; d->ccr |= CCR_SRC_AMODE_POSTINC; if (port_window) { d->ccr |= CCR_DST_AMODE_DBLIDX; if (port_window_bytes >= 64) d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; else if (port_window_bytes >= 32) d->csdp = CSDP_DST_BURST_32 | CSDP_DST_PACKED; else if (port_window_bytes >= 16) d->csdp = CSDP_DST_BURST_16 | CSDP_DST_PACKED; } else { d->ccr |= CCR_DST_AMODE_CONSTANT; } } d->cicr = CICR_DROP_IE | CICR_BLOCK_IE; Loading @@ -927,6 +989,9 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr |= CCR_TRIGGER_SRC; d->cicr |= CICR_MISALIGNED_ERR_IE | CICR_TRANS_ERR_IE; if (port_window) d->csdp |= CSDP_WRITE_LAST_NON_POSTED; } if (od->plat->errata & DMA_ERRATA_PARALLEL_CHANNELS) d->clnk_ctrl = c->dma_ch; Loading @@ -952,6 +1017,16 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( osg->addr = sg_dma_address(sgent); osg->en = en; osg->fn = sg_dma_len(sgent) / frame_bytes; if (port_window && dir == DMA_MEM_TO_DEV) { osg->ei = 1; /* * One frame covers the port_window and by configure * the source frame index to be -1 * (port_window - 1) * we instruct the sDMA that after a frame is processed * it should move back to the start of the window. */ osg->fi = -(port_window_bytes - 1); } if (d->using_ll) { osg->t2_desc = dma_pool_alloc(od->desc_pool, GFP_ATOMIC, Loading Loading @@ -1247,10 +1322,8 @@ static int omap_dma_terminate_all(struct dma_chan *chan) omap_dma_stop(c); } if (c->cyclic) { c->cyclic = false; c->paused = false; } vchan_get_all_descriptors(&c->vc, &head); spin_unlock_irqrestore(&c->vc.lock, flags); Loading @@ -1269,28 +1342,66 @@ static void omap_dma_synchronize(struct dma_chan *chan) static int omap_dma_pause(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); struct omap_dmadev *od = to_omap_dma_dev(chan->device); unsigned long flags; int ret = -EINVAL; bool can_pause = false; /* Pause/Resume only allowed with cyclic mode */ if (!c->cyclic) return -EINVAL; spin_lock_irqsave(&od->irq_lock, flags); if (!c->paused) { omap_dma_stop(c); if (!c->desc) goto out; if (c->cyclic) can_pause = true; /* * We do not allow DMA_MEM_TO_DEV transfers to be paused. * From the AM572x TRM, 16.1.4.18 Disabling a Channel During Transfer: * "When a channel is disabled during a transfer, the channel undergoes * an abort, unless it is hardware-source-synchronized …". * A source-synchronised channel is one where the fetching of data is * under control of the device. In other words, a device-to-memory * transfer. So, a destination-synchronised channel (which would be a * memory-to-device transfer) undergoes an abort if the the CCR_ENABLE * bit is cleared. * From 16.1.4.20.4.6.2 Abort: "If an abort trigger occurs, the channel * aborts immediately after completion of current read/write * transactions and then the FIFO is cleaned up." The term "cleaned up" * is not defined. TI recommends to check that RD_ACTIVE and WR_ACTIVE * are both clear _before_ disabling the channel, otherwise data loss * will occur. * The problem is that if the channel is active, then device activity * can result in DMA activity starting between reading those as both * clear and the write to DMA_CCR to clear the enable bit hitting the * hardware. If the DMA hardware can't drain the data in its FIFO to the * destination, then data loss "might" occur (say if we write to an UART * and the UART is not accepting any further data). */ else if (c->desc->dir == DMA_DEV_TO_MEM) can_pause = true; if (can_pause && !c->paused) { ret = omap_dma_stop(c); if (!ret) c->paused = true; } out: spin_unlock_irqrestore(&od->irq_lock, flags); return 0; return ret; } static int omap_dma_resume(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); struct omap_dmadev *od = to_omap_dma_dev(chan->device); unsigned long flags; int ret = -EINVAL; /* Pause/Resume only allowed with cyclic mode */ if (!c->cyclic) return -EINVAL; spin_lock_irqsave(&od->irq_lock, flags); if (c->paused) { if (c->paused && c->desc) { mb(); /* Restore channel link register */ Loading @@ -1298,9 +1409,11 @@ static int omap_dma_resume(struct dma_chan *chan) omap_dma_start(c, c->desc); c->paused = false; ret = 0; } spin_unlock_irqrestore(&od->irq_lock, flags); return 0; return ret; } static int omap_dma_chan_init(struct omap_dmadev *od) Loading
include/linux/dmaengine.h +8 −0 Original line number Diff line number Diff line Loading @@ -336,6 +336,12 @@ enum dma_slave_buswidth { * may or may not be applicable on memory sources. * @dst_maxburst: same as src_maxburst but for destination target * mutatis mutandis. * @src_port_window_size: The length of the register area in words the data need * to be accessed on the device side. It is only used for devices which is using * an area instead of a single register to receive the data. Typically the DMA * loops in this area in order to transfer the data. * @dst_port_window_size: same as src_port_window_size but for the destination * port. * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill * with 'true' if peripheral should be flow controller. Direction will be * selected at Runtime. Loading Loading @@ -363,6 +369,8 @@ struct dma_slave_config { enum dma_slave_buswidth dst_addr_width; u32 src_maxburst; u32 dst_maxburst; u32 src_port_window_size; u32 dst_port_window_size; bool device_fc; unsigned int slave_id; }; Loading