/**
 * 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;
}
/**
 * Deactivate a BAM DMA pipe
 *
 * This function deactivates a BAM DMA pipe.
 *
 * @dev - pointer to BAM-DMA device descriptor
 *
 * @bam - pointer to BAM device descriptor
 *
 * @pipe_index - pipe index
 *
 * @return 0 on success, negative value on error
 *
 */
static int sps_dma_deactivate_pipe_atomic(struct bamdma_device *dev,
					  struct sps_bam *bam,
					  u32 pipe_index)
{
	u32 channel;

	if (dev->bam != bam)
		return SPS_ERROR;
	if (pipe_index >= dev->num_pipes)
		return SPS_ERROR;
	if (dev->pipes[pipe_index] != PIPE_ACTIVE)
		return SPS_ERROR;	/* Pipe is not active */

	SPS_DBG("BAM-DMA: deactivate pipe %d", pipe_index);

	/* Mark pipe inactive */
	dev->pipes[pipe_index] = PIPE_INACTIVE;

	/*
	 * Channel must be reset when either pipe is disabled, so just always
	 * reset regardless of other pipe's state
	 */
	channel = pipe_index / 2;
	dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel),
			    DMA_CHNL_ENABLE, 0);

	/* If the peer pipe is also inactive, reset the channel */
	if (sps_dma_check_pipes(dev, pipe_index) == DMA_PIPES_BOTH_DISABLED) {
		/* Free channel if allocated internally */
		if (dev->chans[channel].state == DMA_CHAN_STATE_ALLOC_INT)
			dev->chans[channel].state = DMA_CHAN_STATE_FREE;
	}

	return 0;
}
Exemple #3
0
static int sps_dma_deactivate_pipe_atomic(struct bamdma_device *dev,
					  struct sps_bam *bam,
					  u32 pipe_index)
{
	u32 channel;

	if (dev->bam != bam)
		return SPS_ERROR;
	if (pipe_index >= dev->num_pipes)
		return SPS_ERROR;
	if (dev->pipes[pipe_index] != PIPE_ACTIVE)
		return SPS_ERROR;	

	SPS_DBG2("sps:BAM-DMA: deactivate pipe %d", pipe_index);

	
	dev->pipes[pipe_index] = PIPE_INACTIVE;

	channel = pipe_index / 2;
	dma_write_reg_field(dev->virt_addr, DMA_CHNL_CONFIG(channel),
			    DMA_CHNL_ENABLE, 0);

	
	if (sps_dma_check_pipes(dev, pipe_index) == DMA_PIPES_BOTH_DISABLED) {
		
		if (dev->chans[channel].state == DMA_CHAN_STATE_ALLOC_INT)
			dev->chans[channel].state = DMA_CHAN_STATE_FREE;
	}

	return 0;
}
/**
 * Initialize BAM DMA device
 *
 */
int sps_dma_device_init(u32 h)
{
	struct bamdma_device *dev;
	struct sps_bam_props *props;
	u32 chan;
	int result = SPS_ERROR;

	mutex_lock(&bam_dma_lock);

	/* Find a free BAM-DMA device slot */
	dev = NULL;
	if (bam_dma_dev[0].bam != NULL) {
		SPS_ERR("BAM-DMA BAM device already initialized.");
		goto exit_err;
	} else {
		dev = &bam_dma_dev[0];
	}

	/* Record BAM */
	memset(dev, 0, sizeof(*dev));
	dev->h = h;
	dev->bam = sps_h2bam(h);

	if (dev->bam == NULL) {
		SPS_ERR("BAM-DMA BAM device is not found from the handle.");
		goto exit_err;
	}

	/* Map the BAM DMA device into virtual space, if necessary */
	props = &dev->bam->props;
	dev->phys_addr = props->periph_phys_addr;
	if (props->periph_virt_addr != NULL) {
		dev->virt_addr = props->periph_virt_addr;
		dev->virtual_mapped = false;
	} else {
		if (props->periph_virt_size == 0) {
			SPS_ERR("Unable to map BAM DMA IO memory: %x %x",
			 dev->phys_addr, props->periph_virt_size);
			goto exit_err;
		}

		dev->virt_addr = ioremap(dev->phys_addr,
					  props->periph_virt_size);
		if (dev->virt_addr == NULL) {
			SPS_ERR("Unable to map BAM DMA IO memory: %x %x",
				dev->phys_addr, props->periph_virt_size);
			goto exit_err;
		}
		dev->virtual_mapped = true;
	}
	dev->hwio = (void *) dev->virt_addr;

	/* Is the BAM-DMA device locally controlled? */
	if ((props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
		SPS_DBG("BAM-DMA is controlled locally: %x",
			dev->phys_addr);
		dev->local = true;
	} else {
		SPS_DBG("BAM-DMA is controlled remotely: %x",
			dev->phys_addr);
		dev->local = false;
	}

	/*
	 * Enable the BAM DMA and determine the number of pipes/channels.
	 * Leave the BAM-DMA enabled, since it is always a shared device.
	 */
	if (sps_dma_device_enable(dev))
		goto exit_err;

	dev->num_pipes = dev->bam->props.num_pipes;

	/* Disable all channels */
	if (dev->local)
		for (chan = 0; chan < (dev->num_pipes / 2); chan++) {
			dma_write_reg_field(dev->virt_addr,
					    DMA_CHNL_CONFIG(chan),
					    DMA_CHNL_ENABLE, 0);
		}

	result = 0;
exit_err:
	if (result) {
		if (dev != NULL) {
			if (dev->virtual_mapped)
				iounmap(dev->virt_addr);

			dev->bam = NULL;
		}
	}

	mutex_unlock(&bam_dma_lock);

	return result;
}
Exemple #5
0
int sps_dma_device_init(u32 h)
{
	struct bamdma_device *dev;
	struct sps_bam_props *props;
	u32 chan;
	int result = SPS_ERROR;

	mutex_lock(&bam_dma_lock);

	
	dev = NULL;
	if (bam_dma_dev[0].bam != NULL) {
		SPS_ERR("sps:BAM-DMA BAM device is already initialized.");
		goto exit_err;
	} else {
		dev = &bam_dma_dev[0];
	}

	
	memset(dev, 0, sizeof(*dev));
	dev->h = h;
	dev->bam = sps_h2bam(h);

	if (dev->bam == NULL) {
		SPS_ERR("sps:BAM-DMA BAM device is not found "
				"from the handle.");
		goto exit_err;
	}

	
	props = &dev->bam->props;
	dev->phys_addr = props->periph_phys_addr;
	if (props->periph_virt_addr != NULL) {
		dev->virt_addr = props->periph_virt_addr;
		dev->virtual_mapped = false;
	} else {
		if (props->periph_virt_size == 0) {
			SPS_ERR("sps:Unable to map BAM DMA IO memory: %x %x",
			 dev->phys_addr, props->periph_virt_size);
			goto exit_err;
		}

		dev->virt_addr = ioremap(dev->phys_addr,
					  props->periph_virt_size);
		if (dev->virt_addr == NULL) {
			SPS_ERR("sps:Unable to map BAM DMA IO memory: %x %x",
				dev->phys_addr, props->periph_virt_size);
			goto exit_err;
		}
		dev->virtual_mapped = true;
	}
	dev->hwio = (void *) dev->virt_addr;

	
	if ((props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
		SPS_DBG2("sps:BAM-DMA is controlled locally: %x",
			dev->phys_addr);
		dev->local = true;
	} else {
		SPS_DBG2("sps:BAM-DMA is controlled remotely: %x",
			dev->phys_addr);
		dev->local = false;
	}

	if (sps_dma_device_enable(dev))
		goto exit_err;

	dev->num_pipes = dev->bam->props.num_pipes;

	
	if (dev->local)
		for (chan = 0; chan < (dev->num_pipes / 2); chan++) {
			dma_write_reg_field(dev->virt_addr,
					    DMA_CHNL_CONFIG(chan),
					    DMA_CHNL_ENABLE, 0);
		}

	result = 0;
exit_err:
	if (result) {
		if (dev != NULL) {
			if (dev->virtual_mapped)
				iounmap(dev->virt_addr);

			dev->bam = NULL;
		}
	}

	mutex_unlock(&bam_dma_lock);

	return result;
}