Exemplo n.º 1
0
static void mxc_v4l2out_timer_handler(unsigned long arg)
{
	int index;
	unsigned long timeout;
	vout_data *vout = (vout_data *) arg;

	/* DPRINTK("timer handler:\n"); */

	/* If timer occurs before IPU h/w is ready, then set the state to
	   paused and the timer will be set again when next buffer is queued. */
	if (vout->ipu_buf[vout->next_rdy_ipu_buf] != -1) {
		DPRINTK("IPU buffer busy\n");
		vout->state = STATE_STREAM_PAUSED;
		return;
	}

	/* Dequeue buffer and pass to IPU */
	index = dequeue_buf(&vout->ready_q);
	if (index == -1) {	/* no buffers ready, should never occur */
		printk("mxc_v4l2out: timer - no queued buffers ready\n");
		return;
	}
	g_buf_dq_cnt++;
	vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
	if (ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
				      vout->next_rdy_ipu_buf,
				      vout->queue_buf_paddr[index]) < 0) {
		DPRINTK("unable to update buffer %d address\n",
			vout->next_rdy_ipu_buf);
		return;
	}
	if (ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
			      vout->next_rdy_ipu_buf) < 0) {
		DPRINTK("unable to set IPU buffer ready\n");
	}
	vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;

	/* Setup timer for next buffer */
	index = peek_next_buf(&vout->ready_q);
	if (index != -1) {
		timeout = timeval_to_jiffies(&vout->v4l2_bufs[index].timestamp);
		if (!timeout) {
			/* if timestamp is 0, then default to 30fps */
			timeout = vout->start_jiffies +
			    msecs_to_jiffies(vout->frame_count * 33);
		} else {	/* Adjust time from time of day to jiffies */
			timeout -= vout->start_tod_jiffies;
		}
		if (mod_timer(&vout->output_timer, timeout))
			DPRINTK("warning: timer was already set\n");

		vout->frame_count++;
	} else {
		vout->state = STATE_STREAM_PAUSED;
	}
}
Exemplo n.º 2
0
/*!
 * V4L2 interface - ioctl function
 *
 * @param inode      struct inode *
 *
 * @param file       struct file *
 *
 * @param ioctlnr    unsigned int
 *
 * @param arg        void *
 *
 * @return           0 success, ENODEV for invalid device instance,
 *                   -1 for other errors.
 */
static int
mxc_v4l2out_do_ioctl(struct inode *inode, struct file *file,
		     unsigned int ioctlnr, void *arg)
{
	struct video_device *dev = file->private_data;
	vout_data *vout = video_get_drvdata(dev);
	int retval = 0;
	int i = 0;

	if (!vout)
		return -ENODEV;

	/* make this _really_ smp-safe */
	if (down_interruptible(&vout->busy_lock))
		return -EINTR;

	switch (ioctlnr) {
	case VIDIOC_QUERYCAP:
		{
			struct v4l2_capability *cap = arg;
			strcpy(cap->driver, "mxc_v4l2_output");
			cap->version = 0;
			cap->capabilities =
			    V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
			retval = 0;
			break;
		}
	case VIDIOC_G_FMT:
		{
			struct v4l2_format *gf = arg;
			retval = mxc_v4l2out_g_fmt(vout, gf);
			break;
		}
	case VIDIOC_S_FMT:
		{
			struct v4l2_format *sf = arg;
			if (vout->state != STATE_STREAM_OFF) {
				retval = -EBUSY;
				break;
			}
			retval = mxc_v4l2out_s_fmt(vout, sf);
			break;
		}
	case VIDIOC_REQBUFS:
		{
			struct v4l2_requestbuffers *req = arg;
			if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
			    (req->memory != V4L2_MEMORY_MMAP)) {
				DPRINTK
				    ("VIDIOC_REQBUFS: incorrect buffer type\n");
				retval = -EINVAL;
				break;
			}

			if (req->count == 0) {
				mxc_v4l2out_streamoff(vout);
				if (vout->queue_buf_paddr[0] != 0) {
					mxc_free_buffers(vout->queue_buf_paddr,
							 vout->buffer_cnt);
					DPRINTK
					    ("VIDIOC_REQBUFS: freed buffers\n");
				}
				vout->buffer_cnt = 0;
				break;
			}

			if (vout->queue_buf_paddr[0] != 0) {
				DPRINTK
				    ("VIDIOC_REQBUFS: Cannot allocate buffers\n");
				retval = -EBUSY;
				break;
			}

			if (req->count < MIN_FRAME_NUM) {
				req->count = MIN_FRAME_NUM;
			} else if (req->count > MAX_FRAME_NUM) {
				req->count = MAX_FRAME_NUM;
			}
			vout->buffer_cnt = req->count;

			retval = mxc_allocate_buffers(vout->queue_buf_paddr,
						      vout->buffer_cnt,
						      PAGE_ALIGN(vout->v2f.fmt.
								 pix.
								 sizeimage));
			if (retval < 0)
				break;

			/* Init buffer queues */
			vout->done_q.head = 0;
			vout->done_q.tail = 0;
			vout->ready_q.head = 0;
			vout->ready_q.tail = 0;

			for (i = 0; i < vout->buffer_cnt; i++) {
				memset(&(vout->v4l2_bufs[i]), 0,
				       sizeof(vout->v4l2_bufs[i]));
				vout->v4l2_bufs[i].flags = 0;
				vout->v4l2_bufs[i].memory = V4L2_MEMORY_MMAP;
				vout->v4l2_bufs[i].index = i;
				vout->v4l2_bufs[i].type =
				    V4L2_BUF_TYPE_VIDEO_OUTPUT;
				vout->v4l2_bufs[i].length =
				    PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage);
				vout->v4l2_bufs[i].m.offset =
				    (unsigned long)vout->queue_buf_paddr[i];
				vout->v4l2_bufs[i].timestamp.tv_sec = 0;
				vout->v4l2_bufs[i].timestamp.tv_usec = 0;
			}
			break;
		}
	case VIDIOC_QUERYBUF:
		{
			struct v4l2_buffer *buf = arg;
			u32 type = buf->type;
			int index = buf->index;

			if ((type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
			    (index >= vout->buffer_cnt)) {
				DPRINTK
				    ("VIDIOC_QUERYBUFS: incorrect buffer type\n");
				retval = -EINVAL;
				break;
			}
			down(&vout->param_lock);
			memcpy(buf, &(vout->v4l2_bufs[index]), sizeof(*buf));
			up(&vout->param_lock);
			break;
		}
	case VIDIOC_QBUF:
		{
			struct v4l2_buffer *buf = arg;
			int index = buf->index;
			u32 lock_flags;

			if ((buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
			    (index >= vout->buffer_cnt) || (buf->flags != 0)) {
				retval = -EINVAL;
				break;
			}

			DPRINTK("VIDIOC_QBUF: %d\n", buf->index);

			spin_lock_irqsave(&g_lock, lock_flags);

			memcpy(&(vout->v4l2_bufs[index]), buf, sizeof(*buf));
			vout->v4l2_bufs[index].flags |= V4L2_BUF_FLAG_QUEUED;

			g_buf_q_cnt++;
			queue_buf(&vout->ready_q, index);
			if (vout->state == STATE_STREAM_PAUSED) {
				unsigned long timeout =
				    timeval_to_jiffies(&vout->v4l2_bufs[index].
						       timestamp);
				if (!timeout) {
					/* if timestamp is 0, then default to 30fps */
					timeout = vout->start_jiffies +
					    msecs_to_jiffies(vout->frame_count *
							     33);
				} else {	/* Adjust time from time of day to jiffies */
					timeout -= vout->start_tod_jiffies;
				}
				vout->output_timer.expires = timeout;
				DPRINTK("QBUF: frame #%u timeout @ %u jiffies, "
					"current = %u\n",
					vout->frame_count, timeout, jiffies);
				add_timer(&vout->output_timer);
				vout->state = STATE_STREAM_ON;
				vout->frame_count++;
			}

			spin_unlock_irqrestore(&g_lock, lock_flags);
			break;
		}
	case VIDIOC_DQBUF:
		{
			struct v4l2_buffer *buf = arg;
			int idx;

/*                DPRINTK("VIDIOC_DQBUF: q size = %d\n",
                        queue_size(&vout->done_q));
*/
			if ((queue_size(&vout->done_q) == 0) &&
			    (file->f_flags & O_NONBLOCK)) {
				retval = -EAGAIN;
				break;
			}

			if (!wait_event_interruptible_timeout(vout->v4l_bufq,
							      queue_size(&vout->
									 done_q)
							      != 0, 2 * HZ)) {
				printk("VIDIOC_DQBUF: timeout\n");
				retval = -ETIME;
				break;
			} else if (signal_pending(current)) {
				printk("VIDIOC_DQBUF: interrupt received\n");
				vout->state = STATE_STREAM_STOPPING;
				retval = -ERESTARTSYS;
				break;
			}
			idx = dequeue_buf(&vout->done_q);
			if (idx == -1) {	/* No frame free */
				printk
				    ("VIDIOC_DQBUF: no free buffers, returning\n");
				retval = -EAGAIN;
				break;
			}
			if ((vout->v4l2_bufs[idx].flags & V4L2_BUF_FLAG_DONE) ==
			    0)
				printk
				    ("VIDIOC_DQBUF: buffer in done q, but not "
				     "flagged as done\n");

			vout->v4l2_bufs[idx].flags = 0;
			memcpy(buf, &(vout->v4l2_bufs[idx]), sizeof(*buf));
			DPRINTK("VIDIOC_DQBUF: %d\n", buf->index);
			break;
		}
	case VIDIOC_STREAMON:
		{
			struct timeval t;
			do_gettimeofday(&t);
			vout->start_tod_jiffies =
			    timeval_to_jiffies(&t) - jiffies;
			vout->frame_count = 2;
			vout->start_jiffies = jiffies;
			DPRINTK("VIDIOC_STREAMON: start time = %u jiffies, "
				"tod adjustment = %u\n",
				vout->start_jiffies, vout->start_tod_jiffies);

			retval = mxc_v4l2out_streamon(vout);
			break;
		}
	case VIDIOC_STREAMOFF:
		{
			retval = mxc_v4l2out_streamoff(vout);
			break;
		}
	case VIDIOC_G_CTRL:
		{
			retval = mxc_get_v42lout_control(vout, arg);
			break;
		}
	case VIDIOC_S_CTRL:
		{
			retval = mxc_set_v42lout_control(vout, arg);
			break;
		}
	case VIDIOC_CROPCAP:
		{
			struct v4l2_cropcap *cap = arg;

			if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
				retval = -EINVAL;
				break;
			}
			cap->bounds = vout->crop_bounds[vout->cur_disp_output];
			cap->defrect = vout->crop_bounds[vout->cur_disp_output];
			retval = 0;
			break;
		}
	case VIDIOC_G_CROP:
		{
			struct v4l2_crop *crop = arg;

			if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
				retval = -EINVAL;
				break;
			}
			crop->c = vout->crop_current;
			break;
		}
	case VIDIOC_S_CROP:
		{
			struct v4l2_crop *crop = arg;
			struct v4l2_rect *b =
			    &(vout->crop_bounds[vout->cur_disp_output]);

			if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
				retval = -EINVAL;
				break;
			}
			if (crop->c.height < 0) {
				retval = -EINVAL;
				break;
			}
			if (crop->c.width < 0) {
				retval = -EINVAL;
				break;
			}

			if (crop->c.top < b->top)
				crop->c.top = b->top;
			if (crop->c.top > b->top + b->height)
				crop->c.top = b->top + b->height;
			if (crop->c.height > b->top - crop->c.top + b->height)
				crop->c.height =
				    b->top - crop->c.top + b->height;

			if (crop->c.left < b->left)
				crop->c.top = b->left;
			if (crop->c.left > b->left + b->width)
				crop->c.top = b->left + b->width;
			if (crop->c.width > b->left - crop->c.left + b->width)
				crop->c.width =
				    b->left - crop->c.left + b->width;

			/* stride line limitation */
			crop->c.height -= crop->c.height % 8;
			crop->c.width -= crop->c.width % 8;

			vout->crop_current = crop->c;

			vout->sdc_fg_buf_size = vout->crop_current.width *
			    vout->crop_current.height;
			vout->sdc_fg_buf_size *=
			    fmt_to_bpp(SDC_FG_FB_FORMAT) / 8;

			/* Free previously allocated buffer */
			if (vout->display_bufs[0] != NULL) {
				mxc_free_buffers(vout->display_bufs, 2);
			}
			if ((retval = mxc_allocate_buffers(vout->display_bufs,
							   2,
							   vout->
							   sdc_fg_buf_size)) <
			    0) {
				DPRINTK("unable to allocate SDC FG buffers\n");
				retval = -ENOMEM;
				break;
			}
			break;
		}
	case VIDIOC_ENUMOUTPUT:
		{
			struct v4l2_output *output = arg;

			if ((output->index >= 4) ||
			    (vout->output_enabled[output->index] == false)) {
				retval = -EINVAL;
				break;
			}

			if (output->index < 3) {
				*output = mxc_outputs[MXC_V4L2_OUT_2_ADC];
				output->name[4] = '0' + output->index;
			} else {
				*output = mxc_outputs[MXC_V4L2_OUT_2_SDC];
			}
			break;
		}
	case VIDIOC_G_OUTPUT:
		{
			int *p_output_num = arg;

			*p_output_num = vout->cur_disp_output;
			break;
		}
	case VIDIOC_S_OUTPUT:
		{
			int *p_output_num = arg;

			if ((*p_output_num >= 4) ||
			    (vout->output_enabled[*p_output_num] == false)) {
				retval = -EINVAL;
				break;
			}

			if (vout->state != STATE_STREAM_OFF) {
				retval = -EBUSY;
				break;
			}

			vout->cur_disp_output = *p_output_num;
			break;
		}
	case VIDIOC_ENUM_FMT:
	case VIDIOC_TRY_FMT:
	case VIDIOC_QUERYCTRL:
	case VIDIOC_G_PARM:
	case VIDIOC_ENUMSTD:
	case VIDIOC_G_STD:
	case VIDIOC_S_STD:
	case VIDIOC_G_TUNER:
	case VIDIOC_S_TUNER:
	case VIDIOC_G_FREQUENCY:
	case VIDIOC_S_FREQUENCY:
	default:
		retval = -EINVAL;
		break;
	}

	up(&vout->busy_lock);
	return retval;
}
Exemplo n.º 3
0
/*!
 * Start the output stream
 *
 * @param vout      structure vout_data *
 *
 * @return status  0 Success
 */
static int mxc_v4l2out_streamon(vout_data * vout)
{
	ipu_channel_params_t params;
	int pp_in_buf[2];
	u16 out_width;
	u16 out_height;
	ipu_channel_t display_input_ch = MEM_PP_MEM;
	bool use_direct_adc = false;

	if (!vout)
		return -EINVAL;

	if (queue_size(&vout->ready_q) < 2) {
		DPRINTK("2 buffers not been queued yet!\n");
		return -EINVAL;
	}

	out_width = vout->crop_current.width;
	out_height = vout->crop_current.height;

	vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
	vout->ipu_buf[0] = pp_in_buf[0] = dequeue_buf(&vout->ready_q);
	vout->ipu_buf[1] = pp_in_buf[1] = dequeue_buf(&vout->ready_q);

	/* Init Display Channel */
#ifdef CONFIG_FB_MXC_ASYNC_PANEL
	if (vout->cur_disp_output != DISP3) {
		int fbnum = vout->output_fb_num[vout->cur_disp_output];
		mxcfb_set_refresh_mode(registered_fb[fbnum],
				       MXCFB_REFRESH_OFF, 0);
		if (vout->rotate < IPU_ROTATE_90_RIGHT) {
			DPRINTK("Using PP direct to ADC channel\n");
			use_direct_adc = true;
			vout->display_ch = MEM_PP_ADC;
			vout->post_proc_ch = MEM_PP_ADC;

			memset(&params, 0, sizeof(params));
			params.mem_pp_adc.in_width = vout->v2f.fmt.pix.width;
			params.mem_pp_adc.in_height = vout->v2f.fmt.pix.height;
			params.mem_pp_adc.in_pixel_fmt =
			    vout->v2f.fmt.pix.pixelformat;
			params.mem_pp_adc.out_width = out_width;
			params.mem_pp_adc.out_height = out_height;
			params.mem_pp_adc.out_pixel_fmt = SDC_FG_FB_FORMAT;
#ifdef CONFIG_FB_MXC_EPSON_PANEL
			params.mem_pp_adc.out_left = 2 +
			    vout->crop_current.left;
#else
			params.mem_pp_adc.out_left = 12 +
			    vout->crop_current.left;
#endif
			params.mem_pp_adc.out_top = vout->crop_current.top;
			if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
				DPRINTK(KERN_ERR
					"Error initializing PP chan\n");
				return -EINVAL;
			}

			if (ipu_init_channel_buffer(vout->post_proc_ch,
						    IPU_INPUT_BUFFER,
						    params.mem_pp_adc.
						    in_pixel_fmt,
						    params.mem_pp_adc.in_width,
						    params.mem_pp_adc.in_height,
						    params.mem_pp_adc.in_width,
						    vout->rotate,
						    vout->
						    queue_buf_paddr[pp_in_buf
								    [0]],
						    vout->
						    queue_buf_paddr[pp_in_buf
								    [1]]) !=
			    0) {
				DPRINTK(KERN_ERR "Error initializing PP "
					"in buf\n");
				return -EINVAL;
			}
			if (ipu_init_channel_buffer(vout->post_proc_ch,
						    IPU_OUTPUT_BUFFER,
						    params.mem_pp_adc.
						    out_pixel_fmt, out_width,
						    out_height, out_width,
						    vout->rotate, NULL,
						    NULL) != 0) {
				DPRINTK(KERN_ERR "Error initializing PP "
					"output buffer\n");
				return -EINVAL;
			}

		} else {
			DPRINTK("Using ADC SYS2 channel\n");
			vout->display_ch = ADC_SYS2;
			vout->post_proc_ch = MEM_PP_MEM;
			memset(&params, 0, sizeof(params));
			params.adc_sys2.disp = vout->cur_disp_output;
			params.adc_sys2.ch_mode = WriteTemplateNonSeq;
#ifdef CONFIG_FB_MXC_EPSON_PANEL
			params.adc_sys2.out_left = 2 + vout->crop_current.left;
#else
			params.adc_sys2.out_left = 12 + vout->crop_current.left;
#endif
			params.adc_sys2.out_top = vout->crop_current.top;
			if (ipu_init_channel(ADC_SYS2, &params) < 0)
				return -EINVAL;

			if (ipu_init_channel_buffer(vout->display_ch,
						    IPU_INPUT_BUFFER,
						    SDC_FG_FB_FORMAT,
						    out_width, out_height,
						    out_width,
						    IPU_ROTATE_NONE,
						    vout->display_bufs[0],
						    vout->display_bufs[1]) !=
			    0) {
				DPRINTK(KERN_ERR "Error initializing SDC FG "
					"buffer\n");
				return -EINVAL;
			}
		}
	} else
#endif
	{			/* Use SDC */
		DPRINTK("Using SDC channel\n");
		vout->display_ch = MEM_SDC_FG;
		vout->post_proc_ch = MEM_PP_MEM;
		ipu_init_channel(MEM_SDC_FG, NULL);
		ipu_sdc_set_window_pos(MEM_SDC_FG, vout->crop_current.left,
				       vout->crop_current.top);
		if (ipu_init_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER,
					    SDC_FG_FB_FORMAT,
					    out_width, out_height, out_width,
					    IPU_ROTATE_NONE,
					    vout->display_bufs[0],
					    vout->display_bufs[1]) != 0) {
			DPRINTK(KERN_ERR "Error initializing SDC FG buffer\n");
			return -EINVAL;
		}
	}

	/* Init PP */
	if (use_direct_adc == false) {
		if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
			out_width = vout->crop_current.height;
			out_height = vout->crop_current.width;
		}
		memset(&params, 0, sizeof(params));
		params.mem_pp_mem.in_width = vout->v2f.fmt.pix.width;
		params.mem_pp_mem.in_height = vout->v2f.fmt.pix.height;
		params.mem_pp_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
		params.mem_pp_mem.out_width = out_width;
		params.mem_pp_mem.out_height = out_height;
		params.mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
		if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
			DPRINTK(KERN_ERR "Error initializing PP channel\n");
			return -EINVAL;
		}

		if (ipu_init_channel_buffer(vout->post_proc_ch,
					    IPU_INPUT_BUFFER,
					    params.mem_pp_mem.in_pixel_fmt,
					    params.mem_pp_mem.in_width,
					    params.mem_pp_mem.in_height,
					    params.mem_pp_mem.in_width,
					    IPU_ROTATE_NONE,
					    vout->queue_buf_paddr[pp_in_buf[0]],
					    vout->
					    queue_buf_paddr[pp_in_buf[1]]) !=
		    0) {
			DPRINTK(KERN_ERR
				"Error initializing PP input buffer\n");
			return -EINVAL;
		}

		if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
			if (vout->rot_pp_bufs[0]) {
				mxc_free_buffers(vout->rot_pp_bufs, 2);
			}
			if (mxc_allocate_buffers(vout->rot_pp_bufs, 2,
						 vout->sdc_fg_buf_size) < 0) {
				return -ENOBUFS;
			}

			if (ipu_init_channel_buffer(vout->post_proc_ch,
						    IPU_OUTPUT_BUFFER,
						    params.mem_pp_mem.
						    out_pixel_fmt, out_width,
						    out_height, out_width,
						    IPU_ROTATE_NONE,
						    vout->rot_pp_bufs[0],
						    vout->rot_pp_bufs[1]) !=
			    0) {
				DPRINTK(KERN_ERR "Error initializing PP "
					"output buffer\n");
				return -EINVAL;
			}

			if (ipu_init_channel(MEM_ROT_PP_MEM, NULL) != 0) {
				DPRINTK(KERN_ERR "Error initializing PP ROT "
					"channel\n");
				return -EINVAL;
			}

			if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
						    IPU_INPUT_BUFFER,
						    params.mem_pp_mem.
						    out_pixel_fmt, out_width,
						    out_height, out_width,
						    vout->rotate,
						    vout->rot_pp_bufs[0],
						    vout->rot_pp_bufs[1]) !=
			    0) {
				DPRINTK(KERN_ERR "Error initializing PP ROT "
					"input buffer\n");
				return -EINVAL;
			}

			/* swap width and height */
			out_width = vout->crop_current.width;
			out_height = vout->crop_current.height;

			if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
						    IPU_OUTPUT_BUFFER,
						    params.mem_pp_mem.
						    out_pixel_fmt, out_width,
						    out_height, out_width,
						    IPU_ROTATE_NONE,
						    vout->display_bufs[0],
						    vout->display_bufs[1]) !=
			    0) {
				DPRINTK(KERN_ERR "Error initializing PP "
					"output buffer\n");
				return -EINVAL;
			}

			if (ipu_link_channels(vout->post_proc_ch,
					      MEM_ROT_PP_MEM) < 0) {
				return -EINVAL;
			}
			ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0);
			ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 1);

			ipu_enable_channel(MEM_ROT_PP_MEM);

			display_input_ch = MEM_ROT_PP_MEM;
		} else {
			if (ipu_init_channel_buffer(vout->post_proc_ch,
						    IPU_OUTPUT_BUFFER,
						    params.mem_pp_mem.
						    out_pixel_fmt, out_width,
						    out_height, out_width,
						    vout->rotate,
						    vout->display_bufs[0],
						    vout->display_bufs[1]) !=
			    0) {
				DPRINTK(KERN_ERR "Error initializing PP "
					"output buffer\n");
				return -EINVAL;
			}
		}
		if (ipu_link_channels(display_input_ch, vout->display_ch) < 0) {
			DPRINTK(KERN_ERR "Error linking ipu channels\n");
			return -EINVAL;
		}
	}

	vout->state = STATE_STREAM_PAUSED;

	ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
	ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);

	if (use_direct_adc == false) {
		ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0);
		ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1);

		ipu_enable_channel(vout->post_proc_ch);
		ipu_enable_channel(vout->display_ch);
	} else {
		ipu_enable_channel(vout->post_proc_ch);
	}

	return 0;
}
Exemplo n.º 4
0
void ipu_disp_loop_thread(void *arg)
{
	struct decode *dec = (struct decode *)arg;
	DecHandle handle = dec->handle;
	struct vpu_display *disp = dec->disp;
	int index = -1, disp_clr_index, tmp_idx[3] = {0,0,0}, err, mode;
	pthread_attr_t attr;

	ipu_running = 1;

	pthread_attr_init(&attr);
	pthread_attr_setschedpolicy(&attr, SCHED_RR);

	while(1) {
		disp_clr_index = index;
		index = dequeue_buf(&(disp->ipu_q));
		if (index < 0) {
			wait_queue();
			ipu_waiting = 0;
			index = dequeue_buf(&(disp->ipu_q));
			if (index < 0) {
				info_msg("thread is going to finish\n");
				break;
			}
		}

		if (disp->ncount == 0) {
			disp->input.user_def_paddr[0] = disp->ipu_bufs[index].ipu_paddr;
			/* For video de-interlace, Low/Medium motion */
			tmp_idx[0] = index;
		} else if ((disp->deinterlaced == 1) && (disp->input.motion_sel != HIGH_MOTION) && (disp->ncount == 1)) {
			disp->input.user_def_paddr[1] = disp->ipu_bufs[index].ipu_paddr;
			/* For video de-interlace, Low/Medium motion */
			tmp_idx[1] = index;
		} else if ((disp->ncount == 1) || ((disp->deinterlaced == 1) && (disp->input.motion_sel != HIGH_MOTION) &&
						 (disp->ncount == 2))) {
			disp->input.user_def_paddr[disp->ncount] = disp->ipu_bufs[index].ipu_paddr;
			mode = (disp->deinterlaced == 1) ? (OP_STREAM_MODE | TASK_VDI_VF_MODE) : (OP_STREAM_MODE | TASK_PP_MODE);
			err = mxc_ipu_lib_task_init(&(disp->input), NULL, &(disp->output), mode, &(disp->ipu_handle));
			if (err < 0) {
				err_msg("mxc_ipu_lib_task_init failed, err %d\n", err);
				quitflag = 1;
				return;
			}
			/* it only enable ipu task and finish first frame */
			err = mxc_ipu_lib_task_buf_update(&(disp->ipu_handle), 0, 0, 0, NULL, NULL);
			if (err < 0) {
				err_msg("mxc_ipu_lib_task_buf_update failed, err %d\n", err);
				quitflag = 1;
				break;
			}
			/* For video de-interlace, Low/Medium motion */
			tmp_idx[2] = index;
			if ((disp->deinterlaced == 1) && (disp->input.motion_sel != HIGH_MOTION))
				disp_clr_index = tmp_idx[0];
		} else {
			err = mxc_ipu_lib_task_buf_update(&(disp->ipu_handle), disp->ipu_bufs[index].ipu_paddr,
					0, 0, NULL, NULL);
			if (err < 0) {
				err_msg("mxc_ipu_lib_task_buf_update failed, err %d\n", err);
				quitflag = 1;
				break;
			}
			/* For video de-interlace, Low/Medium motion */
			if ((disp->deinterlaced == 1) && (disp->input.motion_sel != HIGH_MOTION)) {
				tmp_idx[0] = tmp_idx[1];
				tmp_idx[1] = tmp_idx[2];
				tmp_idx[2] = index;
				disp_clr_index = tmp_idx[0];
			}
		}

		if ((dec->cmdl->format != STD_MJPG) && (disp_clr_index >= 0) && (!disp->stopping) &&
		    !((disp->deinterlaced == 1) && (disp->input.motion_sel != HIGH_MOTION) && (disp->ncount < 2))) {
			err = vpu_DecClrDispFlag(handle, disp_clr_index);
			if (err) {
				err_msg("vpu_DecClrDispFlag failed Error code %d\n", err);
				quitflag = 1;
				break;
			}
		}
		disp->ncount++;
	}
	mxc_ipu_lib_task_uninit(&(disp->ipu_handle));
	pthread_attr_destroy(&attr);
	info_msg("Disp loop thread exit\n");
	ipu_running = 0;
	return;
}
Exemplo n.º 5
0
static void mxc_v4l2out_timer_handler(unsigned long arg)
{
	int index;
	unsigned long timeout;
	unsigned long lock_flags;
	vout_data *vout = (vout_data *) arg;

	pr_debug("timer handler: %lu\n", jiffies);

	spin_lock_irqsave(&g_lock, lock_flags);

	if ((vout->state == STATE_STREAM_OFF)
	    || (vout->state == STATE_STREAM_STOPPING)) {
		pr_debug("stream has stopped\n");
		goto exit0;
	}

	/*
	 * If timer occurs before PP h/w is ready, then set the state to
	 * paused and the timer will be set again when next buffer is queued
	 * or PP completes.
	 */
	if (vout->ipu_buf[0] != -1) {
		pr_debug("buffer is busy\n");
		vout->state = STATE_STREAM_PAUSED;
		goto exit0;
	}

	/* Dequeue buffer and pass to PP */
	index = dequeue_buf(&vout->ready_q);
	if (index == -1) {	/* no buffers ready, should never occur */
		pr_debug("mxc_v4l2out: timer - no queued buffers ready\n");
		goto exit0;
	}

	g_buf_dq_cnt++;
	vout->frame_count++;
	vout->ipu_buf[0] = index;

	if (pp_ptr((unsigned int)vout->queue_buf_paddr[index])) {
		pr_debug("unable to update buffer\n");
		goto exit0;
	}
#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
	if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
		if (g_fb_enabled
		    && (vout->v4l2_fb.flags != V4L2_FBUF_FLAG_OVERLAY))
			g_pp_ready = 1;
		else if (pp_enable(1)) {
			pr_debug("unable to enable PP\n");
			goto exit0;
		}
	} else if (pp_enable(1)) {
		pr_debug("unable to enable PP\n");
		goto exit0;
	}
#else
	if (pp_enable(1)) {
		pr_debug("unable to enable PP\n");
		goto exit0;
	}
#endif
	pr_debug("enabled index %d\n", index);

	/* Setup timer for next buffer */
	index = peek_next_buf(&vout->ready_q);
	pr_debug("next index %d\n", index);
	if (index != -1) {
		/* if timestamp is 0, then default to 30fps */
		if ((vout->v4l2_bufs[index].timestamp.tv_sec == 0)
		    && (vout->v4l2_bufs[index].timestamp.tv_usec == 0))
			timeout =
			    vout->start_jiffies + vout->frame_count * HZ / 30;
		else
			timeout =
			    get_jiffies(&vout->v4l2_bufs[index].timestamp);

		if (jiffies >= timeout) {
			pr_debug("warning: timer timeout already expired.\n");
		}

		if (mod_timer(&vout->output_timer, timeout))
			pr_debug("warning: timer was already set\n");

		pr_debug("timer handler next schedule: %lu\n", timeout);
	} else {
		vout->state = STATE_STREAM_PAUSED;
		pr_debug("timer handler paused\n");
	}

      exit0:
	spin_unlock_irqrestore(&g_lock, lock_flags);
}
Exemplo n.º 6
0
void ipu_disp_loop_thread(void *arg)
{
	struct DecodingInstance *dec = (struct DecodingInstance *)arg;
	struct vpu_display *disp = dec->disp;
	int index = -1, disp_clr_index, tmp_idx[3] = {0,0,0}, err, mode;
	pthread_attr_t attr;

	ipu_running = 1;

	pthread_attr_init(&attr);
	pthread_attr_setschedpolicy(&attr, SCHED_RR);

	while(1) {
		disp_clr_index = index;
		index = dequeue_buf(&(disp->ipu_q));
		if (index < 0) {
			wait_queue();
			ipu_waiting = 0;
			index = dequeue_buf(&(disp->ipu_q));
			if (index < 0) {
				fputs("thread is going to finish\n", stderr);
				break;
			}
		}

		if (disp->ncount == 0) {
			disp->input.user_def_paddr[0] = disp->ipu_bufs[index].ipu_paddr;
			/* For video de-interlace, Low/Medium motion */
			tmp_idx[0] = index;
		}else if ((disp->ncount == 1)) {
			disp->input.user_def_paddr[disp->ncount] = disp->ipu_bufs[index].ipu_paddr;
			mode = (OP_STREAM_MODE | TASK_PP_MODE);
			err = mxc_ipu_lib_task_init(&(disp->input), NULL, &(disp->output), mode, &(disp->ipu_handle));
			if (err < 0) {
				fprintf(stderr, "mxc_ipu_lib_task_init failed, err %d\n", err);
				quitflag = 1;
				return;
			}
			/* it only enable ipu task and finish first frame */
			err = mxc_ipu_lib_task_buf_update(&(disp->ipu_handle), 0, 0, 0, NULL, NULL);
			if (err < 0) {
				fprintf(stderr, "mxc_ipu_lib_task_buf_update failed, err %d\n", err);
				quitflag = 1;
				break;
			}
		} else {
			err = mxc_ipu_lib_task_buf_update(&(disp->ipu_handle), disp->ipu_bufs[index].ipu_paddr,
					0, 0, NULL, NULL);
			if (err < 0) {
				fprintf(stderr, "mxc_ipu_lib_task_buf_update failed, err %d\n", err);
				quitflag = 1;
				break;
			}

		}

		disp->ncount++;
	}
	mxc_ipu_lib_task_uninit(&(disp->ipu_handle));
	pthread_attr_destroy(&attr);
	fputs("Disp loop thread exit\n", stderr);
	ipu_running = 0;
	return;
}