static void isp_stat_try_enable(struct ispstat *stat)
{
	unsigned long irqflags;

	if (stat->priv == NULL)
		
		return;

	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
	if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing &&
	    stat->buf_alloc_size) {
		stat->update = 1;
		isp_stat_buf_next(stat);
		stat->ops->setup_regs(stat, stat->priv);
		isp_stat_buf_insert_magic(stat, stat->active_buf);

		if (!IS_H3A(stat))
			atomic_set(&stat->buf_err, 0);

		isp_stat_pcr_enable(stat, 1);
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
		dev_dbg(stat->isp->dev, "%s: module is enabled.\n",
			stat->subdev.name);
	} else {
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
	}
}
Beispiel #2
0
static void isp_stat_try_enable(struct ispstat *stat)
{
	unsigned long irqflags;

	if (stat->priv == NULL)
		/* driver wasn't initialised */
		return;

	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
	if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing &&
	    stat->buf_alloc_size) {
		/*
		 * Userspace's requested to enable the engine but it wasn't yet.
		 * Let's do that now.
		 */
		stat->update = 1;
		isp_stat_buf_next(stat);
		stat->ops->setup_regs(stat, stat->priv);
		isp_stat_buf_insert_magic(stat, stat->active_buf);

		/*
		 * H3A module has some hw issues which forces the driver to
		 * ignore next buffers even if it was disabled in the meantime.
		 * On the other hand, Histogram shouldn't ignore buffers anymore
		 * if it's being enabled.
		 */
		if (!IS_H3A(stat))
			atomic_set(&stat->buf_err, 0);

		isp_stat_pcr_enable(stat, 1);
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
		dev_dbg(stat->isp->dev, "%s: module is enabled.\n",
			stat->subdev.name);
	} else {
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
	}
}
Beispiel #3
0
/*
 * __stat_isr - Interrupt handler for statistic drivers
 */
static void __stat_isr(struct ispstat *stat, int from_dma)
{
	int ret = STAT_BUF_DONE;
	int buf_processing;
	unsigned long irqflags;
	struct isp_pipeline *pipe;

	/*
	 * stat->buf_processing must be set before disable module. It's
	 * necessary to not inform too early the buffers aren't busy in case
	 * of SDMA is going to be used.
	 */
	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
	if (stat->state == ISPSTAT_DISABLED) {
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
		return;
	}
	buf_processing = stat->buf_processing;
	stat->buf_processing = 1;
	stat->ops->enable(stat, 0);

	if (buf_processing && !from_dma) {
		if (stat->state == ISPSTAT_ENABLED) {
			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
			dev_err(stat->isp->dev,
				"%s: interrupt occurred when module was still "
				"processing a buffer.\n", stat->subdev.name);
			ret = STAT_NO_BUF;
			goto out;
		} else {
			/*
			 * Interrupt handler was called from streamoff when
			 * the module wasn't busy anymore to ensure it is being
			 * disabled after process last buffer. If such buffer
			 * processing has already started, no need to do
			 * anything else.
			 */
			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
			return;
		}
	}
	spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);

	/* If it's busy we can't process this buffer anymore */
	if (!omap3isp_stat_pcr_busy(stat)) {
		if (!from_dma && stat->ops->buf_process)
			/* Module still need to copy data to buffer. */
			ret = stat->ops->buf_process(stat);
		if (ret == STAT_BUF_WAITING_DMA)
			/* Buffer is not ready yet */
			return;

		spin_lock_irqsave(&stat->isp->stat_lock, irqflags);

		/*
		 * Histogram needs to read its internal memory to clear it
		 * before be disabled. For that reason, common statistic layer
		 * can return only after call stat's buf_process() operator.
		 */
		if (stat->state == ISPSTAT_DISABLING) {
			stat->state = ISPSTAT_DISABLED;
			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
			stat->buf_processing = 0;
			return;
		}
		pipe = to_isp_pipeline(&stat->subdev.entity);
		stat->frame_number = atomic_read(&pipe->frame_number);

		/*
		 * Before this point, 'ret' stores the buffer's status if it's
		 * ready to be processed. Afterwards, it holds the status if
		 * it was processed successfully.
		 */
		ret = isp_stat_buf_process(stat, ret);

		if (likely(!stat->sbl_ovl_recover)) {
			stat->ops->setup_regs(stat, stat->priv);
		} else {
			/*
			 * Using recover config to increase the chance to have
			 * a good buffer processing and make the H3A module to
			 * go back to a valid state.
			 */
			stat->update = 1;
			stat->ops->setup_regs(stat, stat->recover_priv);
			stat->sbl_ovl_recover = 0;

			/*
			 * Set 'update' in case of the module needs to use
			 * regular configuration after next buffer.
			 */
			stat->update = 1;
		}

		isp_stat_buf_insert_magic(stat, stat->active_buf);

		/*
		 * Hack: H3A modules may access invalid memory address or send
		 * corrupted data to userspace if more than 1 SBL overflow
		 * happens in a row without re-writing its buffer's start memory
		 * address in the meantime. Such situation is avoided if the
		 * module is not immediately re-enabled when the ISR misses the
		 * timing to process the buffer and to setup the registers.
		 * Because of that, pcr_enable(1) was moved to inside this 'if'
		 * block. But the next interruption will still happen as during
		 * pcr_enable(0) the module was busy.
		 */
		isp_stat_pcr_enable(stat, 1);
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
	} else {
		/*
		 * If a SBL overflow occurs and the H3A driver misses the timing
		 * to process the buffer, stat->buf_err is set and won't be
		 * cleared now. So the next buffer will be correctly ignored.
		 * It's necessary due to a hw issue which makes the next H3A
		 * buffer to start from the memory address where the previous
		 * one stopped, instead of start where it was configured to.
		 * Do not "stat->buf_err = 0" here.
		 */

		if (stat->ops->buf_process)
			/*
			 * Driver may need to erase current data prior to
			 * process a new buffer. If it misses the timing, the
			 * next buffer might be wrong. So should be ignored.
			 * It happens only for Histogram.
			 */
			atomic_set(&stat->buf_err, 1);

		ret = STAT_NO_BUF;
		dev_dbg(stat->isp->dev, "%s: cannot process buffer, "
					"device is busy.\n", stat->subdev.name);
	}

out:
	stat->buf_processing = 0;
	isp_stat_queue_event(stat, ret != STAT_BUF_DONE);
}
static void __stat_isr(struct ispstat *stat, int from_dma)
{
	int ret = STAT_BUF_DONE;
	int buf_processing;
	unsigned long irqflags;
	struct isp_pipeline *pipe;

	spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
	if (stat->state == ISPSTAT_DISABLED) {
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
		return;
	}
	buf_processing = stat->buf_processing;
	stat->buf_processing = 1;
	stat->ops->enable(stat, 0);

	if (buf_processing && !from_dma) {
		if (stat->state == ISPSTAT_ENABLED) {
			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
			dev_err(stat->isp->dev,
				"%s: interrupt occurred when module was still "
				"processing a buffer.\n", stat->subdev.name);
			ret = STAT_NO_BUF;
			goto out;
		} else {
			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
			return;
		}
	}
	spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);

	
	if (!omap3isp_stat_pcr_busy(stat)) {
		if (!from_dma && stat->ops->buf_process)
			
			ret = stat->ops->buf_process(stat);
		if (ret == STAT_BUF_WAITING_DMA)
			
			return;

		spin_lock_irqsave(&stat->isp->stat_lock, irqflags);

		if (stat->state == ISPSTAT_DISABLING) {
			stat->state = ISPSTAT_DISABLED;
			spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
			stat->buf_processing = 0;
			return;
		}
		pipe = to_isp_pipeline(&stat->subdev.entity);
		stat->frame_number = atomic_read(&pipe->frame_number);

		ret = isp_stat_buf_process(stat, ret);

		if (likely(!stat->sbl_ovl_recover)) {
			stat->ops->setup_regs(stat, stat->priv);
		} else {
			stat->update = 1;
			stat->ops->setup_regs(stat, stat->recover_priv);
			stat->sbl_ovl_recover = 0;

			stat->update = 1;
		}

		isp_stat_buf_insert_magic(stat, stat->active_buf);

		isp_stat_pcr_enable(stat, 1);
		spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
	} else {

		if (stat->ops->buf_process)
			atomic_set(&stat->buf_err, 1);

		ret = STAT_NO_BUF;
		dev_dbg(stat->isp->dev, "%s: cannot process buffer, "
					"device is busy.\n", stat->subdev.name);
	}

out:
	stat->buf_processing = 0;
	isp_stat_queue_event(stat, ret != STAT_BUF_DONE);
}