Exemple #1
0
/*
 * Cancel the video buffers queue.
 *
 * Cancelling the queue marks all buffers on the irq queue as erroneous,
 * wakes them up and removes them from the queue.
 *
 * If the disconnect parameter is set, further calls to uvc_queue_buffer will
 * fail with -ENODEV.
 *
 * This function acquires the irq spinlock and can be called from interrupt
 * context.
 */
void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
{
	struct uvc_buffer *buf;
	unsigned long flags;

	spin_lock_irqsave(&queue->irqlock, flags);
	while (!list_empty(&queue->irqqueue)) {
		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
				       queue);
		list_del(&buf->queue);
		buf->state = UVC_BUF_STATE_ERROR;
		vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
	}
	/* This must be protected by the irqlock spinlock to avoid race
	 * conditions between uvc_buffer_queue and the disconnection event that
	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
	 * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
	 * state outside the queue code.
	 */
	if (disconnect)
		queue->flags |= UVC_QUEUE_DISCONNECTED;
	spin_unlock_irqrestore(&queue->irqlock, flags);
}
/* Called from the IPU IDMAC ISR */
static void mx3_cam_dma_done(void *arg)
{
	struct idmac_tx_desc *desc = to_tx_desc(arg);
	struct dma_chan *chan = desc->txd.chan;
	struct idmac_channel *ichannel = to_idmac_chan(chan);
	struct mx3_camera_dev *mx3_cam = ichannel->client;

	dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
		desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);

	spin_lock(&mx3_cam->lock);
	if (mx3_cam->active) {
		struct vb2_buffer *vb = &mx3_cam->active->vb;
		struct mx3_camera_buffer *buf = to_mx3_vb(vb);

		list_del_init(&buf->queue);
		do_gettimeofday(&vb->v4l2_buf.timestamp);
		vb->v4l2_buf.field = mx3_cam->field;
		vb->v4l2_buf.sequence = mx3_cam->sequence++;
		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
	}

	if (list_empty(&mx3_cam->capture)) {
		mx3_cam->active = NULL;
		spin_unlock(&mx3_cam->lock);

		/*
		 * stop capture - without further buffers IPU_CHA_BUF0_RDY will
		 * not get updated
		 */
		return;
	}

	mx3_cam->active = list_entry(mx3_cam->capture.next,
				     struct mx3_camera_buffer, queue);
	spin_unlock(&mx3_cam->lock);
}
Exemple #3
0
static int fthd_start_streaming(struct vb2_queue *vq, unsigned int count)
{
	struct fthd_private *dev_priv = vb2_get_drv_priv(vq);
	struct h2t_buf_ctx *ctx;
	int i, ret;

	pr_debug("count = %d\n", count);
	ret = fthd_start_channel(dev_priv, 0);
	if (ret)
		return ret;

	for(i = 0; i < FTHD_BUFFERS && count; i++, count--) {
		ctx = dev_priv->h2t_bufs + i;
		if (ctx->state != BUF_DRV_QUEUED)
			continue;

		if (fthd_send_h2t_buffer(dev_priv, ctx)) {
			vb2_buffer_done(ctx->vb, VB2_BUF_STATE_ERROR);
			ctx->state = BUF_ALLOC;
		}
			ctx->state = BUF_HW_QUEUED;
	}
	return 0;
}
Exemple #4
0
static int trigger_dma_transfer_to_buf(struct cssp_cam_dev *dev, struct vb2_buffer *vb)
{
	dma_addr_t dma_buf = vb2_dma_contig_plane_dma_addr(vb, 0);

	if (!dma_buf) {
		/* Is this possible? Release the vb2_buffer with an error here, */
		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
		dev->current_vb = NULL;
		return -ENOMEM;
	}

	dev->dma_tr_params.dst = dma_buf;

	// Enable DMA
	edma_write_slot(dev->dma_ch, &dev->dma_tr_params);

	dev->current_vb = vb;

	// Enable data capture
	dev->mode |= ENABLE;
	writew(dev->mode, dev->reg_base_virt + REG_MODE);

	return 0;
}
Exemple #5
0
void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
{
	struct fimc_vid_cap *cap = &fimc->vid_cap;
	struct fimc_vid_buffer *v_buf;
	struct timeval *tv;
	struct timespec ts;

	if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
		wake_up(&fimc->irq_queue);
		goto done;
	}

	if (!list_empty(&cap->active_buf_q) &&
	    test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {
		ktime_get_real_ts(&ts);

		v_buf = fimc_active_queue_pop(cap);

		tv = &v_buf->vb.v4l2_buf.timestamp;
		tv->tv_sec = ts.tv_sec;
		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
		v_buf->vb.v4l2_buf.sequence = cap->frame_count++;

		vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
	}

	if (!list_empty(&cap->pending_buf_q)) {

		v_buf = fimc_pending_queue_pop(cap);
		fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
		v_buf->index = cap->buf_index;

		/* Move the buffer to the capture active queue */
		fimc_active_queue_add(cap, v_buf);

		dbg("next frame: %d, done frame: %d",
		    fimc_hw_get_frame_index(fimc), v_buf->index);

		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
			cap->buf_index = 0;
	}

	if (cap->active_buf_cnt == 0) {
		if (deq_buf)
			clear_bit(ST_CAPT_RUN, &fimc->state);

		if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
			cap->buf_index = 0;
	} else {
		set_bit(ST_CAPT_RUN, &fimc->state);
	}

	if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
		fimc_capture_config_update(cap->ctx);
done:
	if (cap->active_buf_cnt == 1) {
		fimc_deactivate_capture(fimc);
		clear_bit(ST_CAPT_STREAM, &fimc->state);
	}

	dbg("frame: %d, active_buf_cnt: %d",
	    fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
}
Exemple #6
0
/* This gets called for the Isochronous pipe (video). This is done in
 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
 */
static void pwc_isoc_handler(struct urb *urb)
{
	struct pwc_device *pdev = (struct pwc_device *)urb->context;
	int i, fst, flen;
	unsigned char *iso_buf = NULL;

	if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
	    urb->status == -ESHUTDOWN) {
		PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
		return;
	}

	if (pdev->fill_buf == NULL)
		pdev->fill_buf = pwc_get_next_fill_buf(pdev);

	if (urb->status != 0) {
		const char *errmsg;

		errmsg = "Unknown";
		switch(urb->status) {
			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;
			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;
			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break;
			case -ETIME:		errmsg = "Device does not respond"; break;
		}
		PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
			  urb->status, errmsg);
		/* Give up after a number of contiguous errors */
		if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
		{
			PWC_ERROR("Too many ISOC errors, bailing out.\n");
			if (pdev->fill_buf) {
				vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf,
						VB2_BUF_STATE_ERROR);
				pdev->fill_buf = NULL;
			}
		}
		pdev->vsync = 0; /* Drop the current frame */
		goto handler_end;
	}

	/* Reset ISOC error counter. We did get here, after all. */
	pdev->visoc_errors = 0;

	/* vsync: 0 = don't copy data
		  1 = sync-hunt
		  2 = synched
	 */
	/* Compact data */
	for (i = 0; i < urb->number_of_packets; i++) {
		fst  = urb->iso_frame_desc[i].status;
		flen = urb->iso_frame_desc[i].actual_length;
		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
		if (fst != 0) {
			PWC_ERROR("Iso frame %d has error %d\n", i, fst);
			continue;
		}
		if (flen > 0 && pdev->vsync) {
			struct pwc_frame_buf *fbuf = pdev->fill_buf;

			if (pdev->vsync == 1) {
				fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
				pdev->vsync = 2;
			}

			if (flen + fbuf->filled > pdev->frame_total_size) {
				PWC_ERROR("Frame overflow (%d > %d)\n",
					  flen + fbuf->filled,
					  pdev->frame_total_size);
				pdev->vsync = 0; /* Let's wait for an EOF */
			} else {
				memcpy(fbuf->data + fbuf->filled, iso_buf,
				       flen);
				fbuf->filled += flen;
			}
		}
		if (flen < pdev->vlast_packet_size) {
			/* Shorter packet... end of frame */
			if (pdev->vsync == 2)
				pwc_frame_complete(pdev);
			if (pdev->fill_buf == NULL)
				pdev->fill_buf = pwc_get_next_fill_buf(pdev);
			if (pdev->fill_buf) {
				pdev->fill_buf->filled = 0;
				pdev->vsync = 1;
			}
		}
		pdev->vlast_packet_size = flen;
	}

handler_end:
	i = usb_submit_urb(urb, GFP_ATOMIC);
	if (i != 0)
		PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
Exemple #7
0
static void pwc_frame_complete(struct pwc_device *pdev)
{
	struct pwc_frame_buf *fbuf = pdev->fill_buf;

	/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
	   frames on the USB wire after an exposure change. This conditition is
	   however detected  in the cam and a bit is set in the header.
	   */
	if (pdev->type == 730) {
		unsigned char *ptr = (unsigned char *)fbuf->data;

		if (ptr[1] == 1 && ptr[0] & 0x10) {
			PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
			pdev->drop_frames += 2;
		}
		if ((ptr[0] ^ pdev->vmirror) & 0x01) {
			pwc_snapshot_button(pdev, ptr[0] & 0x01);
		}
		if ((ptr[0] ^ pdev->vmirror) & 0x02) {
			if (ptr[0] & 0x02)
				PWC_TRACE("Image is mirrored.\n");
			else
				PWC_TRACE("Image is normal.\n");
		}
		pdev->vmirror = ptr[0] & 0x03;
		/* Sometimes the trailer of the 730 is still sent as a 4 byte packet
		   after a short frame; this condition is filtered out specifically. A 4 byte
		   frame doesn't make sense anyway.
		   So we get either this sequence:
		   drop_bit set -> 4 byte frame -> short frame -> good frame
		   Or this one:
		   drop_bit set -> short frame -> good frame
		   So we drop either 3 or 2 frames in all!
		   */
		if (fbuf->filled == 4)
			pdev->drop_frames++;
	} else if (pdev->type == 740 || pdev->type == 720) {
		unsigned char *ptr = (unsigned char *)fbuf->data;
		if ((ptr[0] ^ pdev->vmirror) & 0x01) {
			pwc_snapshot_button(pdev, ptr[0] & 0x01);
		}
		pdev->vmirror = ptr[0] & 0x03;
	}

	/* In case we were instructed to drop the frame, do so silently. */
	if (pdev->drop_frames > 0) {
		pdev->drop_frames--;
	} else {
		/* Check for underflow first */
		if (fbuf->filled < pdev->frame_total_size) {
			PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
				       " discarded.\n", fbuf->filled);
		} else {
			fbuf->vb.field = V4L2_FIELD_NONE;
			fbuf->vb.sequence = pdev->vframe_count;
			vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
			pdev->fill_buf = NULL;
			pdev->vsync = 0;
		}
	} /* !drop_frames */
	pdev->vframe_count++;
}
Exemple #8
0
/* Called for each 256-byte image chunk.
 * First word identifies the chunk, followed by 240 words of image
 * data and padding. */
static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
{
	int frame_id, odd, chunk_no;
	u32 *frame;
	struct usbtv_buf *buf;
	unsigned long flags;

	/* Ignore corrupted lines. */
	if (!USBTV_MAGIC_OK(chunk))
		return;
	frame_id = USBTV_FRAME_ID(chunk);
	odd = USBTV_ODD(chunk);
	chunk_no = USBTV_CHUNK_NO(chunk);
	if (chunk_no >= usbtv->n_chunks)
		return;

	/* Beginning of a frame. */
	if (chunk_no == 0) {
		usbtv->frame_id = frame_id;
		usbtv->chunks_done = 0;
	}

	if (usbtv->frame_id != frame_id)
		return;

	spin_lock_irqsave(&usbtv->buflock, flags);
	if (list_empty(&usbtv->bufs)) {
		/* No free buffers. Userspace likely too slow. */
		spin_unlock_irqrestore(&usbtv->buflock, flags);
		return;
	}

	/* First available buffer. */
	buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list);
	frame = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);

	/* Copy the chunk data. */
	usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd);
	usbtv->chunks_done++;

	/* Last chunk in a field */
	if (chunk_no == usbtv->n_chunks-1) {
		/* Last chunk in a frame, signalling an end */
		if (odd && !usbtv->last_odd) {
			int size = vb2_plane_size(&buf->vb.vb2_buf, 0);
			enum vb2_buffer_state state = usbtv->chunks_done ==
				usbtv->n_chunks ?
				VB2_BUF_STATE_DONE :
				VB2_BUF_STATE_ERROR;

			buf->vb.field = V4L2_FIELD_INTERLACED;
			buf->vb.sequence = usbtv->sequence++;
			buf->vb.vb2_buf.timestamp = ktime_get_ns();
			vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
			vb2_buffer_done(&buf->vb.vb2_buf, state);
			list_del(&buf->list);
		}
		usbtv->last_odd = odd;
	}

	spin_unlock_irqrestore(&usbtv->buflock, flags);
}
Exemple #9
0
int msm_mctl_pp_proc_cmd(struct msm_cam_media_controller *p_mctl,
                         struct msm_mctl_pp_cmd *pp_cmd)
{
    int rc = 0;
    struct msm_mctl_pp_frame_buffer pp_buffer;
    struct msm_frame_buffer *buf = NULL;
    void __user *argp = (void __user *)pp_cmd->value;
    int msg_type = VFE_MSG_OUTPUT_V;
    unsigned long flags;

    switch (pp_cmd->id) {
    case MCTL_CMD_GET_FRAME_BUFFER: {
        if (copy_from_user(&pp_buffer, pp_cmd->value,
                           sizeof(pp_buffer)))
            return -EFAULT;
        msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path);
        buf = msm_mctl_get_free_buf(p_mctl, msg_type);
        pp_buffer.buf_handle = (uint32_t)buf;
        if (copy_to_user((void *)argp,
                         &pp_buffer,
                         sizeof(struct msm_mctl_pp_frame_buffer))) {
            ERR_COPY_TO_USER();
            rc = -EFAULT;
        }
        break;
    }
    case MCTL_CMD_PUT_FRAME_BUFFER: {
        if (copy_from_user(&pp_buffer, pp_cmd->value,
                           sizeof(pp_buffer)))
            return -EFAULT;
        msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path);
        buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
        msm_mctl_put_free_buf(p_mctl, msg_type, buf);
        break;
    }
    case MCTL_CMD_DIVERT_FRAME_PP_PATH: {
        struct msm_mctl_pp_divert_pp divert_pp;
        if (copy_from_user(&divert_pp, pp_cmd->value,
                           sizeof(divert_pp)))
            return -EFAULT;
        D("%s: PP_PATH, path=%d",
          __func__, divert_pp.path);
        spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
        p_mctl->pp_info.pp_ctrl.pp_msg_type = divert_pp.path;
        spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
        D("%s: pp path = %d", __func__,
          p_mctl->pp_info.pp_ctrl.pp_msg_type);
        break;
    }
    case MCTL_CMD_DIVERT_FRAME_PP_DONE: {
        struct msm_frame_buffer *buf = NULL;
        if (copy_from_user(&pp_buffer, pp_cmd->value,
                           sizeof(pp_buffer)))
            return -EFAULT;
        buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
        msg_type = msm_mctl_pp_path_to_msg_type(
                       pp_buffer.path);
        if (msm_mctl_buf_del(p_mctl, msg_type, buf) == 0) {
            vb2_buffer_done(&buf->vidbuf,
                            VB2_BUF_STATE_DONE);
        }
    }
    break;
    default:
        rc = -EPERM;
        break;
    }
    return rc;
}
/*
 * omap3isp_video_buffer_next - Complete the current buffer and return the next
 * @video: ISP video object
 *
 * Remove the current video buffer from the DMA queue and fill its timestamp and
 * field count before handing it back to videobuf2.
 *
 * For capture video nodes the buffer state is set to VB2_BUF_STATE_DONE if no
 * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise.
 * For video output nodes the buffer state is always set to VB2_BUF_STATE_DONE.
 *
 * The DMA queue is expected to contain at least one buffer.
 *
 * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
 * empty.
 */
struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
{
	struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
	enum isp_pipeline_state state;
	struct isp_buffer *buf;
	unsigned long flags;

	spin_lock_irqsave(&video->irqlock, flags);
	if (WARN_ON(list_empty(&video->dmaqueue))) {
		spin_unlock_irqrestore(&video->irqlock, flags);
		return NULL;
	}

	buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
			       irqlist);
	list_del(&buf->irqlist);
	spin_unlock_irqrestore(&video->irqlock, flags);

	v4l2_get_timestamp(&buf->vb.timestamp);

	/* Do frame number propagation only if this is the output video node.
	 * Frame number either comes from the CSI receivers or it gets
	 * incremented here if H3A is not active.
	 * Note: There is no guarantee that the output buffer will finish
	 * first, so the input number might lag behind by 1 in some cases.
	 */
	if (video == pipe->output && !pipe->do_propagation)
		buf->vb.sequence =
			atomic_inc_return(&pipe->frame_number);
	else
		buf->vb.sequence = atomic_read(&pipe->frame_number);

	if (pipe->field != V4L2_FIELD_NONE)
		buf->vb.sequence /= 2;

	buf->vb.field = pipe->field;

	/* Report pipeline errors to userspace on the capture device side. */
	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
		state = VB2_BUF_STATE_ERROR;
		pipe->error = false;
	} else {
		state = VB2_BUF_STATE_DONE;
	}

	vb2_buffer_done(&buf->vb.vb2_buf, state);

	spin_lock_irqsave(&video->irqlock, flags);

	if (list_empty(&video->dmaqueue)) {
		spin_unlock_irqrestore(&video->irqlock, flags);

		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
			state = ISP_PIPELINE_QUEUE_OUTPUT
			      | ISP_PIPELINE_STREAM;
		else
			state = ISP_PIPELINE_QUEUE_INPUT
			      | ISP_PIPELINE_STREAM;

		spin_lock_irqsave(&pipe->lock, flags);
		pipe->state &= ~state;
		if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
			video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
		spin_unlock_irqrestore(&pipe->lock, flags);
		return NULL;
	}

	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
		spin_lock(&pipe->lock);
		pipe->state &= ~ISP_PIPELINE_STREAM;
		spin_unlock(&pipe->lock);
	}

	buf = list_first_entry(&video->dmaqueue, struct isp_buffer,
			       irqlist);

	spin_unlock_irqrestore(&video->irqlock, flags);

	return buf;
}
Exemple #11
0
irqreturn_t vc_handler(struct vcap_dev *dev)
{
	uint32_t irq, timestamp;
	enum rdy_buf vc_buf_status, buf_ind;
	struct vcap_buffer *buf;
	struct vb2_buffer *vb = NULL;
	struct vcap_client_data *c_data;
	struct v4l2_event v4l2_evt;

	irq = readl_relaxed(VCAP_VC_INT_STATUS);

	dprintk(1, "%s: irq=0x%08x\n", __func__, irq);

	v4l2_evt.id = 0;
	if (irq & 0x8000200) {
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
			VCAP_VC_PIX_ERR_EVENT;
		v4l2_event_queue(dev->vfd, &v4l2_evt);
	}
	if (irq & 0x40000200) {
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
			VCAP_VC_LINE_ERR_EVENT;
		v4l2_event_queue(dev->vfd, &v4l2_evt);
	}
	if (irq & 0x20000200) {
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
			VCAP_VC_VSYNC_ERR_EVENT;
		v4l2_event_queue(dev->vfd, &v4l2_evt);
	}
	if (irq & 0x00000800) {
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
			VCAP_VC_NPL_OFLOW_ERR_EVENT;
		v4l2_event_queue(dev->vfd, &v4l2_evt);
	}
	if (irq & 0x00000400) {
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
			VCAP_VC_LBUF_OFLOW_ERR_EVENT;
		v4l2_event_queue(dev->vfd, &v4l2_evt);
	}

	vc_buf_status = irq & VC_BUFFER_WRITTEN;
	dprintk(1, "Done buf status = %d\n", vc_buf_status);

	if (vc_buf_status == VC_NO_BUF) {
		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
		pr_err("VC IRQ shows some error\n");
		return IRQ_HANDLED;
	}

	if (dev->vc_client == NULL) {
		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
		pr_err("VC: There is no active vc client\n");
		return IRQ_HANDLED;
	}
	c_data = dev->vc_client;

	spin_lock(&dev->vc_client->cap_slock);
	if (list_empty(&dev->vc_client->vid_vc_action.active)) {
		/* Just leave we have no new queued buffers */
		spin_unlock(&dev->vc_client->cap_slock);
		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
			VCAP_VC_BUF_OVERWRITE_EVENT;
		v4l2_event_queue(dev->vfd, &v4l2_evt);
		dprintk(1, "We have no more avilable buffers\n");
		return IRQ_HANDLED;
	}
	spin_unlock(&dev->vc_client->cap_slock);

	timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);

	buf_ind = dev->vc_client->vid_vc_action.buf_ind;

	if (vc_buf_status == VC_BUF1N2) {
		/* There are 2 buffer ready */
		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
		return IRQ_HANDLED;
	} else if (buf_ind != vc_buf_status) {
		/* buffer is out of sync */
		writel_relaxed(irq, VCAP_VC_INT_CLEAR);
		return IRQ_HANDLED;
	}

	if (buf_ind == VC_BUF1) {
		dprintk(1, "Got BUF1\n");
		vb = &dev->vc_client->vid_vc_action.buf1->vb;
		spin_lock(&dev->vc_client->cap_slock);
		if (list_empty(&dev->vc_client->vid_vc_action.active)) {
			spin_unlock(&dev->vc_client->cap_slock);
			v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
				VCAP_VC_BUF_OVERWRITE_EVENT;
			v4l2_event_queue(dev->vfd, &v4l2_evt);
			writel_relaxed(irq, VCAP_VC_INT_CLEAR);
			return IRQ_HANDLED;
		}
		buf = list_entry(dev->vc_client->vid_vc_action.active.next,
				struct vcap_buffer, list);
		list_del(&buf->list);
		spin_unlock(&dev->vc_client->cap_slock);
		/* Config vc with this new buffer */
		config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1,
				VCAP_VC_C_ADDR_1);

		vb->v4l2_buf.timestamp.tv_usec = timestamp;
		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
		dev->vc_client->vid_vc_action.buf1 = buf;
		dev->vc_client->vid_vc_action.buf_ind = VC_BUF2;
		irq = VC_BUF1;
	} else {
static irqreturn_t unicam_camera_isr(int irq, void *arg)
{
	struct unicam_camera_dev *unicam_dev = (struct unicam_camera_dev *)arg;
	unsigned int status;
	unsigned int reg_status;
	int ret;
	CSL_CAM_BUFFER_STATUS_st_t bufStatus;
	unsigned int bytes_used;
	unsigned long flags;
	static unsigned int t1 = 0, t2 = 0, fps = 0;

	spin_lock_irqsave(&unicam_dev->lock, flags);
	if (!unicam_dev->streaming) {
		pr_err("Interrupt triggered after stopping camera!\n");
		spin_unlock_irqrestore(&unicam_dev->lock, flags);
		return IRQ_HANDLED;
	} else {
		spin_unlock_irqrestore(&unicam_dev->lock, flags);
	}
	/* has the interrupt occured for Channel 0? */
	reg_status =
	    csl_cam_get_rx_status(unicam_dev->cslCamHandle,
				  (CSL_CAM_RX_STATUS_t *) &status);
	dprintk("received unicam interrupt reg_status=0x%x status=0x%x\n",
		reg_status, status);

	if (status & CSL_CAM_RX_INT) {

		/* get and clear interrupt status */
		reg_status =
		    csl_cam_get_intr_status(unicam_dev->cslCamHandle,
					    (CSL_CAM_INTERRUPT_t *) &status);
		if (status & CSL_CAM_INT_FRAME_START) {
			status = status & ~CSL_CAM_INT_FRAME_START;
			if (reg_status & 0x2000)
				pr_err("Camera: Urgent request was signalled at FS!!!\n");
		}

		if ((status & CSL_CAM_INT_FRAME_END) ||
			(status & CSL_CAM_INT_LINE_COUNT)) {
			struct vb2_buffer *vb = unicam_dev->active;
			status &= ~(CSL_CAM_INT_FRAME_END |
					CSL_CAM_INT_LINE_COUNT);
			fps++;
			if (reg_status & 0x2000)
				pr_err("Camera: Urgent request was signalled at FE!!!!\n");
			if (t1 == 0 && t2 == 0)
				t1 = t2 = jiffies_to_msecs(jiffies);

			t2 = jiffies_to_msecs(jiffies);
			if (t2 - t1 > 1000) {
				printk(" sensor fps = %d \n", fps);
				fps = 0;
				t1 = t2;
			}
			dprintk("frame received");
			/* csl_cam_register_display(unicam_dev->cslCamHandle);*/
			if (!vb)
				goto out;
			/* mark  the buffer done */
			/* queue another buffer and trigger capture */
			if (likely(unicam_dev->skip_frames <= 0)) {
				spin_lock_irqsave(&unicam_dev->lock, flags);
				list_del_init(&to_unicam_camera_vb(vb)->queue);
				spin_unlock_irqrestore(&unicam_dev->lock, flags);
				do_gettimeofday(&vb->v4l2_buf.timestamp);
				vb->v4l2_planes[0].bytesused = 0;

				if (unicam_dev->icd->current_fmt->code ==
				    V4L2_MBUS_FMT_JPEG_1X8) {

					ret =
					    csl_cam_get_buffer_status
					    (unicam_dev->cslCamHandle,
					     CSL_CAM_DATA, &bufStatus);

					if (ret == CSL_CAM_OK) {
						bytes_used =
						    (bufStatus.write_ptr -
						     bufStatus.buffer_st.
						     start_addr);
						vb->v4l2_planes[0].bytesused =
						    bytes_used;
					} else
						dev_warn(unicam_dev->dev,
							 "%s:failed to get buffer status",
							 __func__);
				} else {
					ret =
					    csl_cam_get_buffer_status
					    (unicam_dev->cslCamHandle,
					     CSL_CAM_IMAGE, &bufStatus);
					if (ret == CSL_CAM_OK) {
						dprintk("Buffer Status:");
						dprintk("addr:0x%x size:0x%x"
							"ls:%d wp:0x%x"
							"ppl:%d lpf:%d",
							bufStatus.buffer_st.
							start_addr,
							bufStatus.buffer_st.
							size,
							bufStatus.buffer_st.
							line_stride,
							bufStatus.write_ptr,
							bufStatus.
							bytes_per_line,
							bufStatus.
							lines_per_frame);

					}
				}

				vb2_buffer_done(vb, VB2_BUF_STATE_DONE);

				spin_lock_irqsave(&unicam_dev->lock, flags);
				if (unicam_dev->stopping) {
					up(&unicam_dev->stop_sem);
					unicam_dev->active = NULL;
				} else if (!list_empty(&unicam_dev->capture)) {
					unicam_dev->active =
					    &list_entry(unicam_dev->
							capture.next, struct
							unicam_camera_buffer,
							queue)->vb;
				} else {
Exemple #13
0
static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
		struct vb2_buffer *vb)
{
	dma_addr_t buffer = vb2_dma_contig_plane_paddr(vb, 0);
	void *vaddr = vb2_plane_vaddr(vb, 0);
	struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
	/* XXX: format dependant */
	size_t offset_dmadesc = ALIGN(pix->width * pix->height +
			ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32);
	u32 *dmadesc = vaddr + offset_dmadesc;
	u32 heocher;

	if (priv->cfgstate == at91sam9x5_video_CFG_GOOD_LATCH) {
		heocher = REG_HEOCHER_UPDATEEN;
		priv->cfgstate = at91sam9x5_video_CFG_GOOD;
	} else {
		BUG_ON(priv->cfgstate != at91sam9x5_video_CFG_GOOD);
		heocher = 0;
	}

	debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);

	dmadesc[0] = buffer + priv->y_offset;
	dmadesc[1] = REG_HEOxCTRL_DFETCH;
	dmadesc[2] = buffer + offset_dmadesc;

	if (priv->u_planeno >= 0) {
		dmadesc[3] = vb2_dma_contig_plane_paddr(vb, priv->u_planeno) +
			priv->u_offset;
		dmadesc[4] = REG_HEOxCTRL_DFETCH;
		dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
	}

	if (priv->v_planeno >= 0) {
		dmadesc[6] = vb2_dma_contig_plane_paddr(vb, priv->v_planeno) +
			priv->v_offset;
		dmadesc[7] = REG_HEOxCTRL_DFETCH;
		dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
	}


	debug("HEOCHSR = %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
	if (likely(priv->hwstate == at91sam9x5_video_HW_RUNNING)) {

		at91sam9x5_video_write32(priv, REG_HEOHEAD, dmadesc[2]);

		if (priv->u_planeno >= 0)
			at91sam9x5_video_write32(priv,
					REG_HEOUHEAD, dmadesc[5]);

		if (priv->v_planeno >= 0)
			at91sam9x5_video_write32(priv,
					REG_HEOVHEAD, dmadesc[8]);

		at91sam9x5_video_write32(priv,
				REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);

	} else {

		at91sam9x5_video_write32(priv, REG_HEOADDR, dmadesc[0]);
		at91sam9x5_video_write32(priv, REG_HEOCTRL, dmadesc[1]);
		at91sam9x5_video_write32(priv, REG_HEONEXT, dmadesc[2]);

		if (priv->u_planeno >= 0) {
			at91sam9x5_video_write32(priv,
					REG_HEOUADDR, dmadesc[3]);
			at91sam9x5_video_write32(priv,
					REG_HEOUCTRL, dmadesc[4]);
			at91sam9x5_video_write32(priv,
					REG_HEOUNEXT, dmadesc[5]);
		}

		if (priv->v_planeno >= 0) {
			at91sam9x5_video_write32(priv,
					REG_HEOVADDR, dmadesc[6]);
			at91sam9x5_video_write32(priv,
					REG_HEOVCTRL, dmadesc[7]);
			at91sam9x5_video_write32(priv,
					REG_HEOVNEXT, dmadesc[8]);
		}

		at91sam9x5_video_write32(priv, REG_HEOCHER,
				heocher | REG_HEOCHER_CHEN);

		priv->hwstate = at91sam9x5_video_HW_RUNNING;
	}

	if (priv->cur.vb && at91sam9x5_video_buf_in_use(priv, &priv->cur)) {
		if (priv->next.vb) {
			/* drop next; XXX: is this an error? */
			debug("drop %p\n", priv->next.vb);
			vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_ERROR);
		}
	} else {
		if (priv->cur.vb)
			vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);

		priv->cur = priv->next;
	}
	priv->next.vb = vb;
	priv->next.u_planeno = priv->u_planeno;
	priv->next.v_planeno = priv->v_planeno;
	priv->next.plane_size[0] = priv->plane_size[0];
	priv->next.plane_size[1] = priv->plane_size[1];
	priv->next.plane_size[2] = priv->plane_size[2];
}
static void mx3_videobuf_queue(struct vb2_buffer *vb)
{
	struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
	struct mx3_camera_dev *mx3_cam = ici->priv;
	struct mx3_camera_buffer *buf = to_mx3_vb(vb);
	struct dma_async_tx_descriptor *txd = buf->txd;
	struct idmac_channel *ichan = to_idmac_chan(txd->chan);
	struct idmac_video_param *video = &ichan->params.video;
	dma_cookie_t cookie;
	u32 fourcc = icd->current_fmt->host_fmt->fourcc;
	unsigned long flags;

	/* This is the configuration of one sg-element */
	video->out_pixel_fmt	= fourcc_to_ipu_pix(fourcc);

	if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
		/*
		 * If the IPU DMA channel is configured to transport
		 * generic 8-bit data, we have to set up correctly the
		 * geometry parameters upon the current pixel format.
		 * So, since the DMA horizontal parameters are expressed
		 * in bytes not pixels, convert these in the right unit.
		 */
		int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
						icd->current_fmt->host_fmt);
		BUG_ON(bytes_per_line <= 0);

		video->out_width	= bytes_per_line;
		video->out_height	= icd->user_height;
		video->out_stride	= bytes_per_line;
	} else {
		/*
		 * For IPU known formats the pixel unit will be managed
		 * successfully by the IPU code
		 */
		video->out_width	= icd->user_width;
		video->out_height	= icd->user_height;
		video->out_stride	= icd->user_width;
	}

#ifdef DEBUG
	/* helps to see what DMA actually has written */
	if (vb2_plane_vaddr(vb, 0))
		memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
#endif

	spin_lock_irqsave(&mx3_cam->lock, flags);
	list_add_tail(&buf->queue, &mx3_cam->capture);

	if (!mx3_cam->active)
		mx3_cam->active = buf;

	spin_unlock_irq(&mx3_cam->lock);

	cookie = txd->tx_submit(txd);
	dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n",
		cookie, sg_dma_address(&buf->sg));

	if (cookie >= 0)
		return;

	spin_lock_irq(&mx3_cam->lock);

	/* Submit error */
	list_del_init(&buf->queue);

	if (mx3_cam->active == buf)
		mx3_cam->active = NULL;

	spin_unlock_irqrestore(&mx3_cam->lock, flags);
	vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
}
Exemple #15
0
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
			const unsigned char *src, int len,
			enum dmx_buffer_flags *buffer_flags)
{
	unsigned long flags = 0;
	void *vbuf = NULL;
	int todo = len;
	unsigned char *psrc = (unsigned char *)src;
	int ll = 0;

	/*
	 * normal case: This func is called twice from demux driver
	 * one with valid src pointer, second time with NULL pointer
	 */
	if (!src || !len)
		return 0;
	spin_lock_irqsave(&ctx->slock, flags);
	if (buffer_flags && *buffer_flags) {
		ctx->flags |= *buffer_flags;
		*buffer_flags = 0;
	}
	while (todo) {
		if (!ctx->buf) {
			if (list_empty(&ctx->dvb_q)) {
				dprintk(3, "[%s] Buffer overflow!!!\n",
					ctx->name);
				break;
			}

			ctx->buf = list_entry(ctx->dvb_q.next,
					      struct dvb_buffer, list);
			ctx->remain = vb2_plane_size(&ctx->buf->vb, 0);
			ctx->offset = 0;
		}

		if (!dvb_vb2_is_streaming(ctx)) {
			vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_ERROR);
			list_del(&ctx->buf->list);
			ctx->buf = NULL;
			break;
		}

		/* Fill buffer */
		ll = min(todo, ctx->remain);
		vbuf = vb2_plane_vaddr(&ctx->buf->vb, 0);
		memcpy(vbuf + ctx->offset, psrc, ll);
		todo -= ll;
		psrc += ll;

		ctx->remain -= ll;
		ctx->offset += ll;

		if (ctx->remain == 0) {
			vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
			list_del(&ctx->buf->list);
			ctx->buf = NULL;
		}
	}

	if (ctx->nonblocking && ctx->buf) {
		vb2_set_plane_payload(&ctx->buf->vb, 0, ll);
		vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
		list_del(&ctx->buf->list);
		ctx->buf = NULL;
	}
	spin_unlock_irqrestore(&ctx->slock, flags);

	if (todo)
		dprintk(1, "[%s] %d bytes are dropped.\n", ctx->name, todo);
	else
		dprintk(3, "[%s]\n", ctx->name);

	dprintk(3, "[%s] %d bytes are copied\n", ctx->name, len - todo);
	return (len - todo);
}
static irqreturn_t unicam_camera_isr(int irq, void *arg)
{
	struct unicam_camera_dev *unicam_dev = (struct unicam_camera_dev *)arg;
#if 1
	struct v4l2_subdev *sd = soc_camera_to_subdev(unicam_dev->icd);
#endif
	int ret;
	struct int_desc idesc;
	struct rx_stat_list rx;
	u32 isr_status, raw_stat;
	static unsigned int t1 = 0, t2 = 0, fps = 0;
	struct buffer_desc im0;
	dma_addr_t dma_addr;
	unsigned long flags;

	/* has the interrupt occured for Channel 0? */
	memset(&rx, 0x00, sizeof(struct rx_stat_list));
	raw_stat = mm_csi0_get_rx_stat(&rx, 1);
	if (atomic_read(&unicam_dev->streaming) == 0) {
		memset(&idesc, 0x00, sizeof(struct int_desc));
		isr_status = mm_csi0_get_int_stat(&idesc, 1);
		pr_err("ISR triggered after stop stat=0x%x istat=0x%x\n",
			raw_stat, isr_status);

		goto out;
	} else if (rx.is) {
		memset(&idesc, 0x00, sizeof(struct int_desc));
		isr_status = mm_csi0_get_int_stat(&idesc, 1);
		if (idesc.fsi) {
			if (rx.ps)
				pr_info("Panic at frame start\n");
		}

		if (idesc.fei || idesc.lci){
			struct vb2_buffer *vb = unicam_dev->active;
			/* FS and FE handling */
			if (rx.ps)
				pr_info("Panic at frame or lineend\n");
			fps++;
			if (t1 == 0 && t2 == 0)
				t1 = t2 = jiffies_to_msecs(jiffies);

			t2 = jiffies_to_msecs(jiffies);
			if (t2 - t1 > 1000) {
				pr_info(" sensor fps = %d panic count %d\n",
						fps, unicam_dev->panic_count);
				fps = 0;
				t1 = t2;
			}
			atomic_set(&unicam_dev->cam_triggered, 0);
			/*atomic_set(&unicam_dev->retry_count, 0);
			del_timer(&(unicam_dev->unicam_timer));*/
			pr_debug("frame received");
			if (!vb)
			{
				pr_err("%s: vb is not active\n",__func__);
				goto out;
			}

			if (unicam_dev->skip_frames <= 0) {
				struct v4l2_control ctrl;
				int ret = -1;
				ctrl.value = 0;
				ctrl.id = V4L2_CID_CAMERA_READ_MODE_CHANGE_REG;
				ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl);

				if ((ret >= 0) && (ctrl.value > 0)) {
					/* capture mode is not ready yet */
					unicam_dev->skip_frames = ctrl.value;
					pr_info("%s: sensor mode change in process ,need_skip_frame=%d\n",
					__func__, ctrl.value);
				}
			}
			if (likely(unicam_dev->skip_frames <= 0)) {
				spin_lock_irqsave(&unicam_dev->lock, flags);
				list_del_init(&to_unicam_camera_vb(vb)->queue);
				spin_unlock_irqrestore(&unicam_dev->lock,
								flags);
				do_gettimeofday(&vb->v4l2_buf.timestamp);
				vb->v4l2_planes[0].bytesused = 0;

				if (unicam_dev->icd->current_fmt->code ==
				    V4L2_MBUS_FMT_JPEG_1X8) {
				} else {
					ret = 1;
				}

				vb2_buffer_done(vb, VB2_BUF_STATE_DONE);

				spin_lock_irqsave(&unicam_dev->lock, flags);
				if (atomic_read(&unicam_dev->stopping) == 1) {
					up(&unicam_dev->stop_sem);
					unicam_dev->active = NULL;
				} else if (!list_empty(&unicam_dev->capture)) {
						unicam_dev->active =
						    &list_entry(unicam_dev->
							capture.next, struct
 							unicam_camera_buffer,
								queue)->vb;
				} else {
Exemple #17
0
/*
 * omap4iss_video_buffer_next - Complete the current buffer and return the next
 * @video: ISS video object
 *
 * Remove the current video buffer from the DMA queue and fill its timestamp,
 * field count and state fields before waking up its completion handler.
 *
 * For capture video nodes, the buffer state is set to VB2_BUF_STATE_DONE if no
 * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise.
 *
 * The DMA queue is expected to contain at least one buffer.
 *
 * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
 * empty.
 */
struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
{
	struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
	enum iss_pipeline_state state;
	struct iss_buffer *buf;
	unsigned long flags;
	struct timespec ts;

	spin_lock_irqsave(&video->qlock, flags);
	if (WARN_ON(list_empty(&video->dmaqueue))) {
		spin_unlock_irqrestore(&video->qlock, flags);
		return NULL;
	}

	buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
			       list);
	list_del(&buf->list);
	spin_unlock_irqrestore(&video->qlock, flags);

	ktime_get_ts(&ts);
	buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
	buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;

	/* Do frame number propagation only if this is the output video node.
	 * Frame number either comes from the CSI receivers or it gets
	 * incremented here if H3A is not active.
	 * Note: There is no guarantee that the output buffer will finish
	 * first, so the input number might lag behind by 1 in some cases.
	 */
	if (video == pipe->output && !pipe->do_propagation)
		buf->vb.v4l2_buf.sequence =
			atomic_inc_return(&pipe->frame_number);
	else
		buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);

	vb2_buffer_done(&buf->vb, pipe->error ?
			VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
	pipe->error = false;

	spin_lock_irqsave(&video->qlock, flags);
	if (list_empty(&video->dmaqueue)) {
		spin_unlock_irqrestore(&video->qlock, flags);
		if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
			state = ISS_PIPELINE_QUEUE_OUTPUT
			      | ISS_PIPELINE_STREAM;
		else
			state = ISS_PIPELINE_QUEUE_INPUT
			      | ISS_PIPELINE_STREAM;

		spin_lock_irqsave(&pipe->lock, flags);
		pipe->state &= ~state;
		if (video->pipe.stream_state == ISS_PIPELINE_STREAM_CONTINUOUS)
			video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN;
		spin_unlock_irqrestore(&pipe->lock, flags);
		return NULL;
	}

	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
		spin_lock(&pipe->lock);
		pipe->state &= ~ISS_PIPELINE_STREAM;
		spin_unlock(&pipe->lock);
	}

	buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
			       list);
	spin_unlock_irqrestore(&video->qlock, flags);
	buf->vb.state = VB2_BUF_STATE_ACTIVE;
	return buf;
}
Exemple #18
0
static irqreturn_t flite_irq_handler(int irq, void *priv)
{
	struct fimc_lite *fimc = priv;
	struct flite_buffer *vbuf;
	unsigned long flags;
	struct timeval *tv;
	struct timespec ts;
	u32 intsrc;

	spin_lock_irqsave(&fimc->slock, flags);

	intsrc = flite_hw_get_interrupt_source(fimc);
	flite_hw_clear_pending_irq(fimc);

	if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) {
		wake_up(&fimc->irq_queue);
		goto done;
	}

	if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) {
		clear_bit(ST_FLITE_RUN, &fimc->state);
		fimc->events.data_overflow++;
	}

	if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) {
		flite_hw_clear_last_capture_end(fimc);
		clear_bit(ST_FLITE_STREAM, &fimc->state);
		wake_up(&fimc->irq_queue);
	}

	if (fimc->out_path != FIMC_IO_DMA)
		goto done;

	if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
	    test_bit(ST_FLITE_RUN, &fimc->state) &&
	    !list_empty(&fimc->active_buf_q) &&
	    !list_empty(&fimc->pending_buf_q)) {
		vbuf = fimc_lite_active_queue_pop(fimc);
		ktime_get_ts(&ts);
		tv = &vbuf->vb.v4l2_buf.timestamp;
		tv->tv_sec = ts.tv_sec;
		tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
		vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
		vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);

		vbuf = fimc_lite_pending_queue_pop(fimc);
		flite_hw_set_output_addr(fimc, vbuf->paddr);
		fimc_lite_active_queue_add(fimc, vbuf);
	}

	if (test_bit(ST_FLITE_CONFIG, &fimc->state))
		fimc_lite_config_update(fimc);

	if (list_empty(&fimc->pending_buf_q)) {
		flite_hw_capture_stop(fimc);
		clear_bit(ST_FLITE_STREAM, &fimc->state);
	}
done:
	set_bit(ST_FLITE_RUN, &fimc->state);
	spin_unlock_irqrestore(&fimc->slock, flags);
	return IRQ_HANDLED;
}
Exemple #19
0
static void cobalt_dma_stream_queue_handler(struct cobalt_stream *s)
{
    struct cobalt *cobalt = s->cobalt;
    int rx = s->video_channel;
    struct m00473_freewheel_regmap __iomem *fw =
        COBALT_CVI_FREEWHEEL(s->cobalt, rx);
    struct m00233_video_measure_regmap __iomem *vmr =
        COBALT_CVI_VMR(s->cobalt, rx);
    struct m00389_cvi_regmap __iomem *cvi =
        COBALT_CVI(s->cobalt, rx);
    struct m00479_clk_loss_detector_regmap __iomem *clkloss =
        COBALT_CVI_CLK_LOSS(s->cobalt, rx);
    struct cobalt_buffer *cb;
    bool skip = false;

    spin_lock(&s->irqlock);

    if (list_empty(&s->bufs)) {
        pr_err("no buffers!\n");
        spin_unlock(&s->irqlock);
        return;
    }

    /* Give the fresh filled up buffer to the user.
     * Note that the interrupt is only sent if the DMA can continue
     * with a new buffer, so it is always safe to return this buffer
     * to userspace. */
    cb = list_first_entry(&s->bufs, struct cobalt_buffer, list);
    list_del(&cb->list);
    spin_unlock(&s->irqlock);

    if (s->is_audio || s->is_output)
        goto done;

    if (s->unstable_frame) {
        uint32_t stat = ioread32(&vmr->irq_status);

        iowrite32(stat, &vmr->irq_status);
        if (!(ioread32(&vmr->status) &
                M00233_STATUS_BITMAP_INIT_DONE_MSK)) {
            cobalt_dbg(1, "!init_done\n");
            if (s->enable_freewheel)
                goto restart_fw;
            goto done;
        }

        if (ioread32(&clkloss->status) &
                M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) {
            iowrite32(0, &clkloss->ctrl);
            iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl);
            cobalt_dbg(1, "no clock\n");
            if (s->enable_freewheel)
                goto restart_fw;
            goto done;
        }
        if ((stat & (M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK |
                     M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK)) ||
                ioread32(&vmr->vactive_area) != s->timings.bt.height ||
                ioread32(&vmr->hactive_area) != s->timings.bt.width) {
            cobalt_dbg(1, "unstable\n");
            if (s->enable_freewheel)
                goto restart_fw;
            goto done;
        }
        if (!s->enable_cvi) {
            s->enable_cvi = true;
            iowrite32(M00389_CONTROL_BITMAP_ENABLE_MSK, &cvi->control);
            goto done;
        }
        if (!(ioread32(&cvi->status) & M00389_STATUS_BITMAP_LOCK_MSK)) {
            cobalt_dbg(1, "cvi no lock\n");
            if (s->enable_freewheel)
                goto restart_fw;
            goto done;
        }
        if (!s->enable_freewheel) {
            cobalt_dbg(1, "stable\n");
            s->enable_freewheel = true;
            iowrite32(0, &fw->ctrl);
            goto done;
        }
        cobalt_dbg(1, "enabled fw\n");
        iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK |
                  M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK,
                  &vmr->control);
        iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK, &fw->ctrl);
        s->enable_freewheel = false;
        s->unstable_frame = false;
        s->skip_first_frames = 2;
        skip = true;
        goto done;
    }
    if (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) {
restart_fw:
        cobalt_dbg(1, "lost lock\n");
        iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK,
                  &vmr->control);
        iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK |
                  M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK,
                  &fw->ctrl);
        iowrite32(0, &cvi->control);
        s->unstable_frame = true;
        s->enable_freewheel = false;
        s->enable_cvi = false;
    }
done:
    if (s->skip_first_frames) {
        skip = true;
        s->skip_first_frames--;
    }
    cb->vb.vb2_buf.timestamp = ktime_get_ns();
    /* TODO: the sequence number should be read from the FPGA so we
       also know about dropped frames. */
    cb->vb.sequence = s->sequence++;
    vb2_buffer_done(&cb->vb.vb2_buf,
                    (skip || s->unstable_frame) ?
                    VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE);
}