static int sdma_config_channel(struct sdma_channel *sdmac) { int ret; sdma_disable_channel(sdmac); sdmac->event_mask0 = 0; sdmac->event_mask1 = 0; sdmac->shp_addr = 0; sdmac->per_addr = 0; if (sdmac->event_id0) { if (sdmac->event_id0 > 32) return -EINVAL; sdma_event_enable(sdmac, sdmac->event_id0); } switch (sdmac->peripheral_type) { case IMX_DMATYPE_DSP: sdma_config_ownership(sdmac, false, true, true); break; case IMX_DMATYPE_MEMORY: sdma_config_ownership(sdmac, false, true, false); break; default: sdma_config_ownership(sdmac, true, true, false); break; } sdma_get_pc(sdmac, sdmac->peripheral_type); if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { sdmac->event_mask1 = 1 << (sdmac->event_id1 % 32); if (sdmac->event_id1 > 31) sdmac->watermark_level |= 1 << 31; sdmac->event_mask0 = 1 << (sdmac->event_id0 % 32); if (sdmac->event_id0 > 31) sdmac->watermark_level |= 1 << 30; } else { sdmac->event_mask0 = 1 << sdmac->event_id0; sdmac->event_mask1 = 1 << (sdmac->event_id0 - 32); } /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ sdmac->shp_addr = sdmac->per_address; } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } ret = sdma_load_context(sdmac); return ret; }
static struct dma_async_tx_descriptor *sdma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; int ret, i, count; int channel = sdmac->channel; struct scatterlist *sg; if (sdmac->status == DMA_IN_PROGRESS) return NULL; sdmac->status = DMA_IN_PROGRESS; sdmac->flags = 0; dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", sg_len, channel); sdmac->direction = direction; ret = sdma_load_context(sdmac); if (ret) goto err_out; if (sg_len > NUM_BD) { dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", channel, sg_len, NUM_BD); ret = -EINVAL; goto err_out; } sdmac->chn_count = 0; for_each_sg(sgl, sg, sg_len, i) { struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; int param; bd->buffer_addr = sg->dma_address; count = sg->length; if (count > 0xffff) { dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n", channel, count, 0xffff); ret = -EINVAL; goto err_out; } bd->mode.count = count; sdmac->chn_count += count; if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) { ret = -EINVAL; goto err_out; } switch (sdmac->word_size) { case DMA_SLAVE_BUSWIDTH_4_BYTES: bd->mode.command = 0; if (count & 3 || sg->dma_address & 3) return NULL; break; case DMA_SLAVE_BUSWIDTH_2_BYTES: bd->mode.command = 2; if (count & 1 || sg->dma_address & 1) return NULL; break; case DMA_SLAVE_BUSWIDTH_1_BYTE: bd->mode.command = 1; break; default: return NULL; } param = BD_DONE | BD_EXTD | BD_CONT; if (i + 1 == sg_len) { param |= BD_INTR; param |= BD_LAST; param &= ~BD_CONT; } dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n", i, count, sg->dma_address, param & BD_WRAP ? "wrap" : "", param & BD_INTR ? " intr" : ""); bd->mode.status = param; } sdmac->num_bd = sg_len; sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; return &sdmac->desc; err_out: sdmac->status = DMA_ERROR; return NULL; }
static int sdma_config_channel(struct sdma_channel *sdmac) { int ret; sdma_disable_channel(sdmac); sdmac->event_mask0 = 0; sdmac->event_mask1 = 0; sdmac->shp_addr = 0; sdmac->per_addr = 0; if (sdmac->event_id0) sdma_event_enable(sdmac, sdmac->event_id0); if (sdmac->event_id1) sdma_event_enable(sdmac, sdmac->event_id1); switch (sdmac->peripheral_type) { case IMX_DMATYPE_DSP: sdma_config_ownership(sdmac, false, true, true); break; case IMX_DMATYPE_MEMORY: sdma_config_ownership(sdmac, false, true, false); break; default: sdma_config_ownership(sdmac, true, true, false); break; } sdma_get_pc(sdmac, sdmac->peripheral_type); if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) && (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { if (sdmac->event_id0 > 31) { sdmac->watermark_level |= 1 << 28; sdmac->event_mask0 |= 0; sdmac->event_mask1 |= 1 << ((sdmac->event_id0)%32); } else { sdmac->event_mask0 |= 1 << ((sdmac->event_id0)%32); sdmac->event_mask1 |= 0; } if (sdmac->event_id1 > 31) { sdmac->watermark_level |= 1 << 29; sdmac->event_mask0 |= 0; sdmac->event_mask1 |= 1 << ((sdmac->event_id1)%32); } else { sdmac->event_mask0 |= 1 << ((sdmac->event_id1)%32); sdmac->event_mask1 |= 0; } sdmac->watermark_level |= (unsigned int)(3<<11); sdmac->watermark_level |= (unsigned int)(1<<31); sdmac->watermark_level |= (unsigned int)(2<<24); } else { if (sdmac->event_id0 > 31) { sdmac->event_mask0 = 0; sdmac->event_mask1 = 1 << ((sdmac->event_id0)%32); } else { sdmac->event_mask0 = 1 << ((sdmac->event_id0)%32); sdmac->event_mask1 = 0; } } /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ switch (sdmac->direction) { case DMA_DEV_TO_DEV: sdmac->per_addr = sdmac->per_address; sdmac->shp_addr = sdmac->per_address2; break; default: sdmac->shp_addr = sdmac->per_address; break; } } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } ret = sdma_load_context(sdmac); return ret; }
static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction) { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; int num_periods = buf_len / period_len; int channel = sdmac->channel; int ret, i = 0, buf = 0; dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); if (sdmac->status == DMA_IN_PROGRESS) return NULL; sdmac->status = DMA_IN_PROGRESS; sdmac->flags |= IMX_DMA_SG_LOOP; sdmac->direction = direction; ret = sdma_load_context(sdmac); if (ret) goto err_out; if (num_periods > NUM_BD) { dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", channel, num_periods, NUM_BD); goto err_out; } if (period_len > 0xffff) { dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n", channel, period_len, 0xffff); goto err_out; } while (buf < buf_len) { struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; int param; bd->buffer_addr = dma_addr; bd->mode.count = period_len; if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) goto err_out; if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES) bd->mode.command = 0; else bd->mode.command = sdmac->word_size; param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR; if (i + 1 == num_periods) param |= BD_WRAP; dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n", i, period_len, dma_addr, param & BD_WRAP ? "wrap" : "", param & BD_INTR ? " intr" : ""); bd->mode.status = param; dma_addr += period_len; buf += period_len; i++; } sdmac->num_bd = num_periods; sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys; return &sdmac->desc; err_out: sdmac->status = DMA_ERROR; return NULL; }