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; } }
/*! * 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; }
/*! * 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(¶ms, 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, ¶ms) != 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(¶ms, 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, ¶ms) < 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(¶ms, 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, ¶ms) != 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; }
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; }
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); }
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; }