/** * 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; }
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; }
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; }