/** * Enable a BAM DMA pipe * */ int sps_dma_pipe_enable(void *bam_arg, u32 pipe_index) { struct sps_bam *bam = bam_arg; struct bamdma_device *dev; struct bamdma_chan *chan; u32 channel; int result = SPS_ERROR; SPS_DBG("sps_dma_pipe_enable.pipe %d", pipe_index); mutex_lock(&bam_dma_lock); dev = sps_dma_find_device((u32) bam); if (dev == NULL) { SPS_ERR("BAM-DMA: invalid BAM"); goto exit_err; } if (pipe_index >= dev->num_pipes) { SPS_ERR("BAM-DMA: BAM %x invalid pipe: %d", bam->props.phys_addr, pipe_index); goto exit_err; } if (dev->pipes[pipe_index] != PIPE_ACTIVE) { SPS_ERR("BAM-DMA: BAM %x pipe %d not active", bam->props.phys_addr, pipe_index); goto exit_err; } /* * The channel must be enabled when the dest/input/write pipe * is enabled */ if (DMA_PIPE_IS_DEST(pipe_index)) { /* Configure and enable the channel */ channel = pipe_index / 2; chan = &dev->chans[channel]; if (chan->threshold != SPS_DMA_THRESHOLD_DEFAULT) dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel), DMA_CHNL_ACT_THRESH, chan->thresh); if (chan->priority != SPS_DMA_PRI_DEFAULT) dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel), DMA_CHNL_WEIGHT, chan->weight); dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel), DMA_CHNL_ENABLE, 1); } result = 0; exit_err: mutex_unlock(&bam_dma_lock); return result; }
/** * Allocate a BAM DMA pipe * */ int sps_dma_pipe_alloc(void *bam_arg, u32 pipe_index, enum sps_mode dir) { struct sps_bam *bam = bam_arg; struct bamdma_device *dev; struct bamdma_chan *chan; u32 channel; int result = SPS_ERROR; if (bam == NULL) { SPS_ERR("BAM context is NULL"); return SPS_ERROR; } /* Check pipe direction */ if ((DMA_PIPE_IS_DEST(pipe_index) && dir != SPS_MODE_DEST) || (DMA_PIPE_IS_SRC(pipe_index) && dir != SPS_MODE_SRC)) { SPS_ERR("BAM-DMA: wrong direction for BAM %x pipe %d", bam->props.phys_addr, pipe_index); return SPS_ERROR; } mutex_lock(&bam_dma_lock); dev = sps_dma_find_device((u32) bam); if (dev == NULL) { SPS_ERR("BAM-DMA: invalid BAM: %x", bam->props.phys_addr); goto exit_err; } if (pipe_index >= dev->num_pipes) { SPS_ERR("BAM-DMA: BAM %x invalid pipe: %d", bam->props.phys_addr, pipe_index); goto exit_err; } if (dev->pipes[pipe_index] != PIPE_INACTIVE) { SPS_ERR("BAM-DMA: BAM %x pipe %d already active", bam->props.phys_addr, pipe_index); goto exit_err; } /* Mark pipe active */ dev->pipes[pipe_index] = PIPE_ACTIVE; /* If channel is not allocated, make an internal allocation */ channel = pipe_index / 2; chan = &dev->chans[channel]; if (chan->state != DMA_CHAN_STATE_ALLOC_EXT && chan->state != DMA_CHAN_STATE_ALLOC_INT) { chan->state = DMA_CHAN_STATE_ALLOC_INT; } result = 0; exit_err: mutex_unlock(&bam_dma_lock); return result; }
/** * Free a BAM DMA channel * */ int sps_free_dma_chan(struct sps_dma_chan *chan) { struct bamdma_device *dev; u32 pipe_index; int result = 0; if (chan == NULL) { SPS_ERR("sps_free_dma_chan. chan is NULL"); return SPS_ERROR; } mutex_lock(&bam_dma_lock); dev = sps_dma_find_device(chan->dev); if (dev == NULL) { SPS_ERR("BAM-DMA: invalid BAM handle: %x", chan->dev); result = SPS_ERROR; goto exit_err; } /* Verify the pipe indices */ pipe_index = chan->dest_pipe_index; if (pipe_index >= dev->num_pipes || ((pipe_index & 1)) || (pipe_index + 1) != chan->src_pipe_index) { SPS_ERR("sps_free_dma_chan. Invalid pipe indices"); SPS_DBG("num_pipes=%d.dest=%d.src=%d.", dev->num_pipes, chan->dest_pipe_index, chan->src_pipe_index); result = SPS_ERROR; goto exit_err; } /* Are both pipes inactive? */ if (dev->chans[pipe_index / 2].state != DMA_CHAN_STATE_ALLOC_EXT || dev->pipes[pipe_index] != PIPE_INACTIVE || dev->pipes[pipe_index + 1] != PIPE_INACTIVE) { SPS_ERR("BAM-DMA: attempt to free active chan %d: %d %d", pipe_index / 2, dev->pipes[pipe_index], dev->pipes[pipe_index + 1]); result = SPS_ERROR; goto exit_err; } /* Free the channel */ dev->chans[pipe_index / 2].state = DMA_CHAN_STATE_FREE; exit_err: mutex_unlock(&bam_dma_lock); return result; }
/** * De-initialize BAM DMA device * */ int sps_dma_device_de_init(u32 h) { struct bamdma_device *dev; u32 pipe_index; u32 chan; int result = 0; mutex_lock(&bam_dma_lock); dev = sps_dma_find_device(h); if (dev == NULL) { SPS_ERR("sps:BAM-DMA: not registered: %x", h); result = SPS_ERROR; goto exit_err; } /* Check for channel leaks */ for (chan = 0; chan < dev->num_pipes / 2; chan++) { if (dev->chans[chan].state != DMA_CHAN_STATE_FREE) { SPS_ERR("sps:BAM-DMA: channel not free: %d", chan); result = SPS_ERROR; dev->chans[chan].state = DMA_CHAN_STATE_FREE; } } for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) { if (dev->pipes[pipe_index] != PIPE_INACTIVE) { SPS_ERR("sps:BAM-DMA: pipe not inactive: %d", pipe_index); result = SPS_ERROR; dev->pipes[pipe_index] = PIPE_INACTIVE; } } /* Disable BAM and BAM-DMA */ if (sps_dma_device_disable(dev)) result = SPS_ERROR; dev->h = BAM_HANDLE_INVALID; dev->bam = NULL; if (dev->virtual_mapped) iounmap(dev->virt_addr); exit_err: mutex_unlock(&bam_dma_lock); return result; }
/** * Free a BAM DMA pipe * */ int sps_dma_pipe_free(void *bam_arg, u32 pipe_index) { struct bamdma_device *dev; struct sps_bam *bam = bam_arg; int result; mutex_lock(&bam_dma_lock); dev = sps_dma_find_device((u32) bam); if (dev == NULL) { SPS_ERR("BAM-DMA: invalid BAM"); result = SPS_ERROR; goto exit_err; } result = sps_dma_deactivate_pipe_atomic(dev, bam, pipe_index); exit_err: mutex_unlock(&bam_dma_lock); return result; }
/** * Allocate a BAM DMA channel * */ int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc, struct sps_dma_chan *chan_info) { struct bamdma_device *dev; struct bamdma_chan *chan; u32 pipe_index; enum bam_dma_thresh_dma thresh = (enum bam_dma_thresh_dma) 0; enum bam_dma_weight_dma weight = (enum bam_dma_weight_dma) 0; int result = SPS_ERROR; if (alloc == NULL || chan_info == NULL) { SPS_ERR("sps_alloc_dma_chan. invalid parameters"); return SPS_ERROR; } /* Translate threshold and priority to hwio values */ if (alloc->threshold != SPS_DMA_THRESHOLD_DEFAULT) { if (alloc->threshold >= 512) thresh = BAM_DMA_THRESH_512; else if (alloc->threshold >= 256) thresh = BAM_DMA_THRESH_256; else if (alloc->threshold >= 128) thresh = BAM_DMA_THRESH_128; else thresh = BAM_DMA_THRESH_64; } weight = alloc->priority; if ((u32)alloc->priority > (u32)BAM_DMA_WEIGHT_HIGH) { SPS_ERR("BAM-DMA: invalid priority: %x", alloc->priority); return SPS_ERROR; } mutex_lock(&bam_dma_lock); dev = sps_dma_find_device(alloc->dev); if (dev == NULL) { SPS_ERR("BAM-DMA: invalid BAM handle: %x", alloc->dev); goto exit_err; } /* Search for a free set of pipes */ for (pipe_index = 0, chan = dev->chans; pipe_index < dev->num_pipes; pipe_index += 2, chan++) { if (chan->state == DMA_CHAN_STATE_FREE) { /* Just check pipes for safety */ if (dev->pipes[pipe_index] != PIPE_INACTIVE || dev->pipes[pipe_index + 1] != PIPE_INACTIVE) { SPS_ERR("BAM-DMA: channel %d state error:%d %d", pipe_index / 2, dev->pipes[pipe_index], dev->pipes[pipe_index + 1]); goto exit_err; } break; /* Found free pipe */ } } if (pipe_index >= dev->num_pipes) { SPS_ERR("BAM-DMA: no free channel. num_pipes = %d", dev->num_pipes); goto exit_err; } chan->state = DMA_CHAN_STATE_ALLOC_EXT; /* Store config values for use when pipes are activated */ chan = &dev->chans[pipe_index / 2]; chan->threshold = alloc->threshold; chan->thresh = thresh; chan->priority = alloc->priority; chan->weight = weight; SPS_DBG("sps_alloc_dma_chan. pipe %d.\n", pipe_index); /* Report allocated pipes to client */ chan_info->dev = dev->h; /* Dest/input/write pipex */ chan_info->dest_pipe_index = pipe_index; /* Source/output/read pipe */ chan_info->src_pipe_index = pipe_index + 1; result = 0; exit_err: mutex_unlock(&bam_dma_lock); return result; }
int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc, struct sps_dma_chan *chan_info) { struct bamdma_device *dev; struct bamdma_chan *chan; u32 pipe_index; enum bam_dma_thresh_dma thresh = (enum bam_dma_thresh_dma) 0; enum bam_dma_weight_dma weight = (enum bam_dma_weight_dma) 0; int result = SPS_ERROR; if (alloc == NULL || chan_info == NULL) { SPS_ERR("sps:sps_alloc_dma_chan. invalid parameters"); return SPS_ERROR; } if (alloc->threshold != SPS_DMA_THRESHOLD_DEFAULT) { if (alloc->threshold >= 512) thresh = BAM_DMA_THRESH_512; else if (alloc->threshold >= 256) thresh = BAM_DMA_THRESH_256; else if (alloc->threshold >= 128) thresh = BAM_DMA_THRESH_128; else thresh = BAM_DMA_THRESH_64; } weight = alloc->priority; if ((u32)alloc->priority > (u32)BAM_DMA_WEIGHT_HIGH) { SPS_ERR("sps:BAM-DMA: invalid priority: %x", alloc->priority); return SPS_ERROR; } mutex_lock(&bam_dma_lock); dev = sps_dma_find_device(alloc->dev); if (dev == NULL) { SPS_ERR("sps:BAM-DMA: invalid BAM handle: %x", alloc->dev); goto exit_err; } for (pipe_index = 0, chan = dev->chans; pipe_index < dev->num_pipes; pipe_index += 2, chan++) { if (chan->state == DMA_CHAN_STATE_FREE) { if (dev->pipes[pipe_index] != PIPE_INACTIVE || dev->pipes[pipe_index + 1] != PIPE_INACTIVE) { SPS_ERR("sps:BAM-DMA: channel %d state " "error:%d %d", pipe_index / 2, dev->pipes[pipe_index], dev->pipes[pipe_index + 1]); goto exit_err; } break; } } if (pipe_index >= dev->num_pipes) { SPS_ERR("sps:BAM-DMA: no free channel. num_pipes = %d", dev->num_pipes); goto exit_err; } chan->state = DMA_CHAN_STATE_ALLOC_EXT; chan = &dev->chans[pipe_index / 2]; chan->threshold = alloc->threshold; chan->thresh = thresh; chan->priority = alloc->priority; chan->weight = weight; SPS_DBG2("sps:sps_alloc_dma_chan. pipe %d.\n", pipe_index); chan_info->dev = dev->h; chan_info->dest_pipe_index = pipe_index; chan_info->src_pipe_index = pipe_index + 1; result = 0; exit_err: mutex_unlock(&bam_dma_lock); return result; }