/**
 * 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;
}
Exemple #4
0
/**
 * 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;
}
Exemple #7
0
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;
}