diff options
author | Mark Gutman <r58412@freescale.com> | 2009-09-03 11:47:32 +0300 |
---|---|---|
committer | Alejandro Gonzalez <alex.gonzalez@digi.com> | 2010-02-12 17:19:20 +0100 |
commit | 6ac248ced7fc410ff2864f6b277caf1f023a900c (patch) | |
tree | 92fa92b322312c163e0df555cfa243ad59217386 /drivers/media | |
parent | 0453bf1ccee9fa13828db12fd0afff28639f853e (diff) |
ENGR00115576 ipuv3: support for 720P upsizing
A new feature is added to support to upsizing by horizontal stripes
via IC PP channels double using.
Signed-off-by: Mark Gutman <r58412@freescale.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/mxc/output/mxc_v4l2_output.c | 298 | ||||
-rw-r--r-- | drivers/media/video/mxc/output/mxc_v4l2_output.h | 8 |
2 files changed, 251 insertions, 55 deletions
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c index 59420597f871..9254db5980c2 100644 --- a/drivers/media/video/mxc/output/mxc_v4l2_output.c +++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c @@ -212,10 +212,12 @@ static u32 fmt_to_bpp(u32 pixelformat) { u32 bpp; - bpp = 8*bytes_per_pixel(pixelformat); + bpp = 8 * bytes_per_pixel(pixelformat); return bpp; } + + static bool format_is_yuv(u32 pixelformat) { switch (pixelformat) { @@ -285,7 +287,9 @@ static irqreturn_t mxc_v4l2out_disp_refresh_irq_handler(int irq, void *dev_id) dev_err(&vout->video_dev->dev, "unable to set IPU buffer ready\n"); } - vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; + /* Non IC split action */ + if (!vout->pp_split) + vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; pending_buffer = 0; @@ -412,8 +416,8 @@ static void mxc_v4l2out_timer_handler(unsigned long arg) } else { if (LOAD_3FIELDS(vout)) { int index_n = index; - index = last_index_n; int index_p = last_index_c; + index = last_index_n; vout->ipu_buf_p[vout->next_rdy_ipu_buf] = index_p; vout->ipu_buf[vout->next_rdy_ipu_buf] = last_index_c = index; vout->ipu_buf_n[vout->next_rdy_ipu_buf] = last_index_n = index_n; @@ -433,9 +437,35 @@ static void mxc_v4l2out_timer_handler(unsigned long arg) vout->v4l2_bufs[index_n].m.offset+aid_field_offset); } else { vout->ipu_buf[vout->next_rdy_ipu_buf] = index; - ret = ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf, - vout->v4l2_bufs[index].m.offset+current_field_offset); + if (vout->pp_split) { + vout->ipu_buf[!vout->next_rdy_ipu_buf] = index; + /* always left stripe */ + ret = ipu_update_channel_buffer(vout->post_proc_ch, + IPU_INPUT_BUFFER, + 0,/* vout->next_rdy_ipu_buf,*/ + (vout->v4l2_bufs[index].m.offset) + + vout->pp_left_stripe.input_column + + current_field_offset); + + /* the U/V offset has to be updated inside of IDMAC */ + /* according to stripe offset */ + ret += ipu_update_channel_offset(vout->post_proc_ch, + IPU_INPUT_BUFFER, + vout->v2f.fmt.pix.pixelformat, + vout->v2f.fmt.pix.width, + vout->v2f.fmt.pix.height, + vout->v2f.fmt.pix.width, + vout->offset.u_offset, + vout->offset.v_offset, + 0, + vout->pp_left_stripe.input_column + current_field_offset); + + } else + ret = ipu_update_channel_buffer(vout->post_proc_ch, + IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf, + vout->v4l2_bufs[index].m.offset + + current_field_offset); } } if (ret < 0) { @@ -462,7 +492,13 @@ static irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id) unsigned long timeout; unsigned long lock_flags = 0; vout_data *vout = dev_id; - + int pp_out_buf_num = 0; + int disp_buf_num = 0; + int disp_buf_num_next = 1; + int pp_out_buf_offset = 0; + int release_buffer = 1; + int eba_offset; + int ret = -1; spin_lock_irqsave(&g_lock, lock_flags); g_irq_cnt++; @@ -473,21 +509,85 @@ static irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id) else last_buf = vout->ipu_buf[vout->next_done_ipu_buf]; + /* If IC split mode on, update output buffer number */ if (last_buf != -1) { - if ((!INTERLACED_CONTENT(vout)) || (vout->next_done_ipu_buf)) { - g_buf_output_cnt++; - vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; - queue_buf(&vout->done_q, last_buf); - wake_up_interruptible(&vout->v4l_bufq); - } - vout->ipu_buf[vout->next_done_ipu_buf] = -1; - if (LOAD_3FIELDS(vout)) { - vout->ipu_buf_p[vout->next_done_ipu_buf] = -1; - vout->ipu_buf_n[vout->next_done_ipu_buf] = -1; + if (vout->pp_split) { + pp_out_buf_num = vout->pp_split_buf_num & 1;/* left/right stripe */ + disp_buf_num = vout->pp_split_buf_num >> 1; + disp_buf_num_next = ((vout->pp_split_buf_num+2) & 3) >> 1; + if (!pp_out_buf_num) {/* next buffer is right stripe*/ + eba_offset = vout->pp_right_stripe.input_column;/*always right stripe*/ + ret = ipu_update_channel_buffer(vout->post_proc_ch, + IPU_INPUT_BUFFER, + 1, /* right stripe */ + (vout->v4l2_bufs[vout->ipu_buf[disp_buf_num]].m.offset) + + eba_offset); + + ret += ipu_update_channel_offset(vout->post_proc_ch, + IPU_INPUT_BUFFER, + vout->v2f.fmt.pix.pixelformat, + vout->v2f.fmt.pix.width, + vout->v2f.fmt.pix.height, + vout->v2f.fmt.pix.width, + vout->offset.u_offset, + vout->offset.v_offset, + 0, + vout->pp_right_stripe.input_column); + + /* select right stripe */ + ret += ipu_select_buffer(vout->post_proc_ch, + IPU_INPUT_BUFFER, 1); + if (ret < 0) + dev_err(&vout->video_dev->dev, + "unable to set IPU buffer ready\n"); + + vout->ipu_buf[vout->next_done_ipu_buf] = -1; + vout->next_done_ipu_buf = !vout->next_done_ipu_buf; + + } else /* right stripe is done, run display refresh */ + ret = ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, + disp_buf_num); + + vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; + + /* offset for next buffer's EBA */ + pp_out_buf_offset = pp_out_buf_num ? vout->pp_right_stripe.output_column : + vout->pp_left_stripe.output_column; + + /* next buffer update */ + eba_offset = vout->display_bufs[disp_buf_num_next] + + pp_out_buf_offset; + + ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, + pp_out_buf_num, eba_offset); + + /* next buffer ready */ + ret = ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, pp_out_buf_num); + + /* next stripe_buffer index 0..3 */ + vout->pp_split_buf_num = (vout->pp_split_buf_num + 1) & 3; + } + + /* release buffer if second stripe is done */ + release_buffer = vout->pp_split ? pp_out_buf_num : 1; + if (release_buffer) { + if ((!INTERLACED_CONTENT(vout)) || (vout->next_done_ipu_buf)) { + g_buf_output_cnt++; + vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; + queue_buf(&vout->done_q, last_buf); + wake_up_interruptible(&vout->v4l_bufq); + } + vout->ipu_buf[vout->next_done_ipu_buf] = -1; + if (LOAD_3FIELDS(vout)) { + vout->ipu_buf_p[vout->next_done_ipu_buf] = -1; + vout->ipu_buf_n[vout->next_done_ipu_buf] = -1; + } + vout->next_done_ipu_buf = !vout->next_done_ipu_buf; } - vout->next_done_ipu_buf = !vout->next_done_ipu_buf; - } - pp_eof = 1; + } /* end of last_buf != -1 */ + + if (release_buffer) + pp_eof = 1; if (vout->state == STATE_STREAM_STOPPING) { if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) { @@ -739,38 +839,93 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, * * @return status 0 Success */ -static int init_PP(ipu_channel_params_t params, vout_data *vout, +static int init_PP(ipu_channel_params_t *params, vout_data *vout, struct device *dev, struct fb_info *fbi, ipu_channel_t *display_input_ch, u16 out_width, u16 out_height) { - 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; + u16 in_width, out_stride; /* stride of output channel */ + unsigned int ipu_ic_out_max_width_size; + if (vout->display_ch == ADC_SYS2) - params.mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT; + params->mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT; else - params.mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi); - if (ipu_init_channel(vout->post_proc_ch, ¶ms) != 0) { + params->mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi); + + out_stride = out_width; + in_width = 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_resize_ratio = 0; /* 0 means unused */ + +#ifdef CONFIG_MXC_IPU_V1 + ipu_ic_out_max_width_size = 800; +#else + ipu_ic_out_max_width_size = 1024; +#endif + /* split IC by two stripes, the by pass is impossible*/ + if (out_width > ipu_ic_out_max_width_size) { + vout->pp_split = 1; + out_stride = 2*out_width; + + + ipu_calc_stripes_sizes( + params->mem_pp_mem.in_width, /* input frame width;>1 */ + params->mem_pp_mem.out_width, /* output frame width; >1 */ + ipu_ic_out_max_width_size, + (((unsigned long long)1) << 32), /* 32bit for fractional*/ + 1, /* equal stripes */ + params->mem_pp_mem.in_pixel_fmt, + params->mem_pp_mem.out_pixel_fmt, + &(vout->pp_left_stripe), + &(vout->pp_right_stripe)); + + + vout->pp_left_stripe.input_column = vout->pp_left_stripe.input_column * + fmt_to_bpp(vout->v2f.fmt.pix.pixelformat) / 8; + vout->pp_left_stripe.output_column = vout->pp_left_stripe.output_column * + fmt_to_bpp(params->mem_pp_mem.out_pixel_fmt) / 8; + vout->pp_right_stripe.input_column = vout->pp_right_stripe.input_column * + fmt_to_bpp(vout->v2f.fmt.pix.pixelformat) / 8; + + + vout->pp_right_stripe.output_column = vout->pp_right_stripe.output_column * + fmt_to_bpp(params->mem_pp_mem.out_pixel_fmt) / 8; + + + + /* updare parameters */ + params->mem_pp_mem.in_width = vout->pp_left_stripe.input_width; + params->mem_pp_mem.out_width = vout->pp_left_stripe.output_width; + out_width = vout->pp_left_stripe.output_width; + /* for using in ic_init*/ + params->mem_pp_mem.out_resize_ratio = vout->pp_left_stripe.irr; + + vout->pp_split_buf_num = 0; + } else + vout->pp_split = 0; + + + if (ipu_init_channel(vout->post_proc_ch, params) != 0) { dev_err(dev, "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_pixel_fmt, + params->mem_pp_mem.in_width, + params->mem_pp_mem.in_height, vout->v2f.fmt.pix.bytesperline / - bytes_per_pixel(params.mem_pp_mem. - in_pixel_fmt), - IPU_ROTATE_NONE, - vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, - vout->v4l2_bufs[vout->ipu_buf[1]].m.offset, - vout->offset.u_offset, - vout->offset.v_offset) != 0) { + bytes_per_pixel(params->mem_pp_mem. + in_pixel_fmt), + IPU_ROTATE_NONE, + vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, + vout->v4l2_bufs[vout->ipu_buf[1]].m.offset, + vout->offset.u_offset, + vout->offset.v_offset) != 0) { dev_err(dev, "Error initializing PP input buffer\n"); return -EINVAL; } @@ -789,9 +944,9 @@ static int init_PP(ipu_channel_params_t params, vout_data *vout, if (ipu_init_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, - params.mem_pp_mem. + params->mem_pp_mem. out_pixel_fmt, out_width, - out_height, out_width, + out_height, out_stride, IPU_ROTATE_NONE, vout->rot_pp_bufs[0], vout->rot_pp_bufs[1], 0, 0) != 0) { @@ -805,9 +960,9 @@ static int init_PP(ipu_channel_params_t params, vout_data *vout, } if (ipu_init_channel_buffer(MEM_ROT_PP_MEM, IPU_INPUT_BUFFER, - params.mem_pp_mem. + params->mem_pp_mem. out_pixel_fmt, out_width, - out_height, out_width, + out_height, out_stride, vout->rotate, vout->rot_pp_bufs[0], vout->rot_pp_bufs[1], 0, 0) != 0) { @@ -818,15 +973,15 @@ static int init_PP(ipu_channel_params_t params, vout_data *vout, /* swap width and height */ if (vout->rotate >= IPU_ROTATE_90_RIGHT) { - out_width = vout->crop_current.width; + out_stride = 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. + params->mem_pp_mem. out_pixel_fmt, out_width, - out_height, out_width, + out_height, out_stride, IPU_ROTATE_NONE, vout->display_bufs[0], vout->display_bufs[1], 0, 0) != 0) { @@ -846,9 +1001,9 @@ static int init_PP(ipu_channel_params_t params, vout_data *vout, } else { if (ipu_init_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, - params.mem_pp_mem. + params->mem_pp_mem. out_pixel_fmt, out_width, - out_height, out_width, + out_height, out_stride, vout->rotate, vout->display_bufs[0], vout->display_bufs[1], 0, 0) != 0) { @@ -856,6 +1011,28 @@ static int init_PP(ipu_channel_params_t params, vout_data *vout, return -EINVAL; } } + + /* fix EBAs for IDMAC channels */ + if (vout->pp_split) { + ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, + 0, + vout->v4l2_bufs[vout->ipu_buf[0]].m.offset + + vout->pp_left_stripe.input_column); + ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, + 1, + vout->v4l2_bufs[vout->ipu_buf[0]].m.offset + + vout->pp_right_stripe.input_column); + ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, + 0, + vout->display_bufs[0] + + vout->pp_left_stripe.output_column); + + ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, + 1, + vout->display_bufs[0] + + vout->pp_right_stripe.output_column); + } + return 0; } @@ -921,8 +1098,15 @@ static int mxc_v4l2out_streamon(vout_data * vout) if (!INTERLACED_CONTENT(vout)) { vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0; vout->ipu_buf[0] = dequeue_buf(&vout->ready_q); - vout->ipu_buf[1] = dequeue_buf(&vout->ready_q); - vout->frame_count = 2; + if (out_width != vout->v2f.fmt.pix.width && /*pp_split*/ + out_height != vout->v2f.fmt.pix.height && + out_width > 1024) { + vout->ipu_buf[1] = vout->ipu_buf[0]; + vout->frame_count = 1; + } else { + vout->ipu_buf[1] = dequeue_buf(&vout->ready_q); + vout->frame_count = 2; + } } else if (!LOAD_3FIELDS(vout)) { vout->ipu_buf[0] = dequeue_buf(&vout->ready_q); vout->ipu_buf[1] = -1; @@ -1063,6 +1247,7 @@ static int mxc_v4l2out_streamon(vout_data * vout) * Bypass IC if resizing and rotation are not needed * Meanwhile, apply IC bypass to SDC only */ + vout->pp_split = 0;/* no pp_split by default */ if (out_width == vout->v2f.fmt.pix.width && out_height == vout->v2f.fmt.pix.height && ipu_can_rotate_in_place(vout->rotate)) { @@ -1169,14 +1354,16 @@ static int mxc_v4l2out_streamon(vout_data * vout) rc = init_VDI(params, vout, dev, fbi, &display_input_ch, out_width, out_height); } else { - rc = init_PP(params, vout, dev, fbi, &display_input_ch, + rc = init_PP(¶ms, vout, dev, fbi, &display_input_ch, out_width, out_height); } if (rc < 0) return rc; - if (ipu_link_channels(display_input_ch, vout->display_ch) < 0) { - dev_err(dev, "Error linking ipu channels\n"); - return -EINVAL; + if (!vout->pp_split) { /* display channel link */ + if (ipu_link_channels(display_input_ch, vout->display_ch) < 0) { + dev_err(dev, "Error linking ipu channels\n"); + return -EINVAL; + } } } @@ -1195,7 +1382,8 @@ static int mxc_v4l2out_streamon(vout_data * vout) ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); } else { ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); - ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1); + if (!vout->pp_split) + ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1); } ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1); diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h index 069edde1e850..45d713222d86 100644 --- a/drivers/media/video/mxc/output/mxc_v4l2_output.h +++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h @@ -132,6 +132,14 @@ typedef struct _vout_data { u32 bytesperline; enum v4l2_field field_fmt; ipu_motion_sel motion_sel; + + /* PP split fot two stripes*/ + int pp_split; /* 0,1 */ + struct stripe_param pp_left_stripe; + struct stripe_param pp_right_stripe; /* struct for split parameters */ + /* IC ouput buffer number. Counting from 0 to 3 */ + int pp_split_buf_num; /* 0..3 */ + } vout_data; #endif |