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>
This commit is contained in:
Mark Gutman
2009-09-03 11:47:32 +03:00
committed by Matt Sealey
parent e18a399aec
commit 732aceb787
11 changed files with 1272 additions and 62 deletions

View File

@@ -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);
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;
}
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;
/* 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, &params) != 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(&params, 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);

View File

@@ -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

View File

@@ -1,5 +1,5 @@
obj-$(CONFIG_MXC_IPU_V1) = mxc_ipu.o
mxc_ipu-objs := ipu_common.o ipu_sdc.o ipu_adc.o ipu_ic.o ipu_csi.o ipu_device.o
mxc_ipu-objs := ipu_common.o ipu_sdc.o ipu_adc.o ipu_ic.o ipu_csi.o ipu_device.o ipu_calc_stripes_sizes.o
obj-$(CONFIG_MXC_IPU_PF) += pf/

View File

@@ -0,0 +1,374 @@
/*
* Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file ipu_calc_stripes_sizes.c
*
* @brief IPU IC functions
*
* @ingroup IPU
*/
#include <linux/module.h>
#include <linux/ipu.h>
#include <asm/div64.h>
#define BPP_32 0
#define BPP_16 3
#define BPP_8 5
#define BPP_24 1
#define BPP_12 4
#define BPP_18 2
static u64 _do_div(u64 a, u32 b)
{
u64 div;
div = a;
do_div(div, b);
return div;
}
static u32 truncate(u32 up, /* 0: down; else: up */
u64 a, /* must be non-negative */
u32 b)
{
u32 d;
u64 div;
div = _do_div(a, b);
d = b * (div >> 32);
if (up && (a > (((u64)d) << 32)))
return d+b;
else
return d;
}
static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
{/* return input_f */
unsigned int f_calculated = 0;
switch (pfs) {
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
f_calculated = 16;
break;
case IPU_PIX_FMT_NV12:
f_calculated = 8;
break;
default:
f_calculated = 0;
break;
}
if (!f_calculated) {
switch (bpp) {
case BPP_32:
f_calculated = 2;
break;
case BPP_16:
f_calculated = 4;
break;
case BPP_8:
case BPP_24:
f_calculated = 8;
break;
case BPP_12:
f_calculated = 16;
break;
case BPP_18:
f_calculated = 32;
break;
default:
f_calculated = 0;
break;
}
}
return f_calculated;
}
static unsigned int m_calc(unsigned int pfs)
{
unsigned int m_calculated = 0;
switch (pfs) {
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_NV12:
m_calculated = 8;
break;
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
m_calculated = 2;
break;
default:
m_calculated = 1;
break;
}
return m_calculated;
}
/* Stripe parameters calculator */
/**************************************************************************
Notes:
MSW = the maximal width allowed for a stripe
i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
cirr = the maximal inverse resizing ratio for which overlap in the input
is requested; typically cirr~2
equal_stripes:
0: each stripe is allowed to have independent parameters
for maximal image quality
1: the stripes are requested to have identical parameters
(except the base address), for maximal performance
If performance is the top priority (above image quality)
Avoid overlap, by setting CIRR = 0
This will also force effectively identical_stripes = 1
Choose IF & OF that corresponds to the same IOX/SX for both stripes
Choose IFW & OFW such that
IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
The function returns an error status:
0: no error
1: invalid input parameters -> aborted without result
Valid parameters should satisfy the following conditions
IFW <= OFW, otherwise downsizing is required
- which is not supported yet
4 <= IFW,OFW, so some interpolation may be needed even without overlap
IM, OM, IF, OF should not vanish
2*IF <= IFW
so the frame can be split to two equal stripes, even without overlap
2*(OF+IF/irr_opt) <= OFW
so a valid positive INW exists even for equal stripes
OF <= MSW, otherwise, the left stripe cannot be sufficiently large
MSW < OFW, so splitting to stripes is required
OFW <= 2*MSW, so two stripes are sufficient
(this also implies that 2<=MSW)
2: OF is not a multiple of OM - not fully-supported yet
Output is produced but OW is not guaranited to be a multiple of OM
4: OFW reduced to be a multiple of OM
8: CIRR > 1: truncated to 1
Overlap is not supported (and not needed) y for upsizing)
**************************************************************************/
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
/* input frame width;>1 */
unsigned int output_frame_width, /* output frame width; >1 */
const unsigned int maximal_stripe_width,
/* the maximal width allowed for a stripe */
const unsigned long long cirr, /* see above */
const unsigned int equal_stripes, /* see above */
u32 input_pixelformat,/* pixel format after of read channel*/
u32 output_pixelformat,/* pixel format after of write channel*/
struct stripe_param *left,
struct stripe_param *right)
{
const unsigned int irr_frac_bits = 13;
const unsigned long irr_steps = 1 << irr_frac_bits;
const u64 dirr = ((u64)1) << (32 - 2);
/* The maximum relative difference allowed between the irrs */
const u64 cr = ((u64)4) << 32;
/* The importance ratio between the two terms in the cost function below */
unsigned int status;
unsigned int temp;
unsigned int onw_min;
unsigned int inw, onw, inw_best = 0;
/* number of pixels in the left stripe NOT hidden by the right stripe */
u64 irr_opt; /* the optimal inverse resizing ratio */
u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
u64 dinw; /* the misalignment between the stripes */
/* (measured in units of input columns) */
u64 difwl, difwr;
/* The number of input columns not reflected in the output */
/* the resizing ratio used for the right stripe is */
/* left->irr and right->irr respectively */
u64 cost, cost_min;
u64 div; /* result of division */
unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
status = 0;
/* M, F calculations */
/* read back pfs from params */
input_f = f_calc(input_pixelformat, 0, NULL);
input_m = 16;
/* BPP should be used in the out_F calc */
/* Temporarily not used */
/* out_F = F_calc(idmac->pfs, idmac->bpp, NULL); */
output_f = 16;
output_m = m_calc(output_pixelformat);
if ((output_frame_width < input_frame_width) || (input_frame_width < 4)
|| (output_frame_width < 4))
return 1;
irr_opt = _do_div((((u64)(input_frame_width - 1)) << 32),
(output_frame_width - 1));
rr_opt = _do_div((((u64)(output_frame_width - 1)) << 32),
(input_frame_width - 1));
if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
|| (input_frame_width < (2 * input_f))
|| ((((u64)output_frame_width) << 32) <
(2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
|| (maximal_stripe_width < output_f)
|| (output_frame_width <= maximal_stripe_width)
|| ((2 * maximal_stripe_width) < output_frame_width))
return 1;
if (output_f % output_m)
status += 2;
temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
if (temp < output_frame_width) {
output_frame_width = temp;
status += 4;
}
if (equal_stripes) {
if ((irr_opt > cirr) /* overlap in the input is not requested */
&& ((input_frame_width % (input_m << 1)) == 0)
&& ((input_frame_width % (input_f << 1)) == 0)
&& ((output_frame_width % (output_m << 1)) == 0)
&& ((output_frame_width % (output_f << 1)) == 0)) {
/* without overlap */
left->input_width = right->input_width = right->input_column =
input_frame_width >> 1;
left->output_width = right->output_width = right->output_column =
output_frame_width >> 1;
left->input_column = right->input_column = 0;
div = _do_div(((((u64)irr_steps) << 32) *
(right->input_width - 1)), (right->output_width - 1));
left->irr = right->irr = truncate(0, div, 1);
} else { /* with overlap */
onw = truncate(0, (((u64)output_frame_width) << 32) >> 1,
output_f);
inw = truncate(0, onw * irr_opt, input_f);
/* this is the maximal inw which allows the same resizing ratio */
/* in both stripes */
onw = truncate(1, (inw * rr_opt), output_f);
div = _do_div((((u64)(irr_steps * inw)) <<
32), onw);
left->irr = right->irr = truncate(0, div, 1);
left->output_width = right->output_width =
output_frame_width - onw;
/* These are valid assignments for output_width, */
/* assuming output_f is a multiple of output_m */
div = (((u64)(left->output_width-1) * (left->irr)) << 32);
div = (((u64)1) << 32) + _do_div(div, irr_steps);
left->input_width = right->input_width = truncate(1, div, input_m);
div = _do_div((((u64)((right->output_width - 1) * right->irr)) <<
32), irr_steps);
difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
div = _do_div((difwr + (((u64)input_f) << 32)), 2);
left->input_column = truncate(0, div, input_f);
/* This splits the truncated input columns evenly */
/* between the left and right margins */
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
}
} else { /* independent stripes */
onw_min = output_frame_width - maximal_stripe_width;
/* onw is a multiple of output_f, in the range */
/* [max(output_f,output_frame_width-maximal_stripe_width),*/
/*min(output_frame_width-2,maximal_stripe_width)] */
/* definitely beyond the cost of any valid setting */
cost_min = (((u64)input_frame_width) << 32) + cr;
onw = truncate(0, ((u64)maximal_stripe_width), output_f);
if (output_frame_width - onw == 1)
onw -= output_f; /* => onw and output_frame_width-1-onw are positive */
inw = truncate(0, onw * irr_opt, input_f);
/* this is the maximal inw which allows the same resizing ratio */
/* in both stripes */
onw = truncate(1, inw * rr_opt, output_f);
do {
div = _do_div((((u64)(irr_steps * inw)) << 32), onw);
left->irr = truncate(0, div, 1);
div = _do_div((((u64)(onw * left->irr)) << 32),
irr_steps);
dinw = (((u64)inw) << 32) - div;
div = _do_div((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
32), irr_steps);
difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
cost = difwl + (((u64)(cr * dinw)) >> 32);
if (cost < cost_min) {
inw_best = inw;
cost_min = cost;
}
inw -= input_f;
onw = truncate(1, inw * rr_opt, output_f);
/* This is the minimal onw which allows the same resizing ratio */
/* in both stripes */
} while (onw >= onw_min);
inw = inw_best;
onw = truncate(1, inw * rr_opt, output_f);
div = _do_div((((u64)(irr_steps * inw)) << 32), onw);
left->irr = truncate(0, div, 1);
left->output_width = onw;
right->output_width = output_frame_width - onw;
/* These are valid assignments for output_width, */
/* assuming output_f is a multiple of output_m */
left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
32, input_m);
div = _do_div((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
32), (right->output_width - 1));
right->irr = truncate(0, div, 1);
temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
if (temp < right->irr)
right->irr = temp;
div = _do_div(((u64)((right->output_width - 1) * right->irr) <<
32), irr_steps);
difwr = (u64)(input_frame_width - 1 - inw) - div;
div = _do_div((difwr + (((u64)input_f) << 32)), 2);
left->input_column = truncate(0, div, input_f);
/* This splits the truncated input columns evenly */
/* between the left and right margins */
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
}
return status;
}
EXPORT_SYMBOL(ipu_calc_stripes_sizes);

View File

@@ -618,6 +618,64 @@ int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
return 0;
}
/*!
* This function is called to initialize a buffer for logical IPU channel.
*
* @param channel Input parameter for the logical channel ID.
*
* @param type Input parameter which buffer to initialize.
*
* @param pixel_fmt Input parameter for pixel format of buffer.
* Pixel format is a FOURCC ASCII code.
*
* @param width Input parameter for width of buffer in pixels.
*
* @param height Input parameter for height of buffer in pixels.
*
* @param stride Input parameter for stride length of buffer
* in pixels.
*
* @param u predefined private u offset for additional cropping,
* zero if not used.
*
* @param v predefined private v offset for additional cropping,
* zero if not used.
*
* @param vertical_offset vertical offset for Y coordinate
* in the existed frame
*
*
* @param horizontal_offset horizontal offset for X coordinate
* in the existed frame
*
*
* @return Returns 0 on success or negative error code on fail
* This function will fail if any buffer is set to ready.
*/
int32_t ipu_update_channel_offset(ipu_channel_t channel, ipu_buffer_t type,
uint32_t pixel_fmt,
uint16_t width, uint16_t height,
uint32_t stride,
uint32_t u, uint32_t v,
uint32_t vertical_offset, uint32_t horizontal_offset)
{
uint32_t reg;
int ret = 0;
unsigned long lock_flags;
uint32_t dma_chan = channel_2_dma(channel, type);
if (dma_chan == IDMA_CHAN_INVALID)
return -EINVAL;
spin_lock_irqsave(&ipu_lock, lock_flags);
ret = -EACCES;
spin_unlock_irqrestore(&ipu_lock, lock_flags);
return ret;
}
EXPORT_SYMBOL(ipu_update_channel_offset);
/*!
* This function is called to set a channel's buffer as ready.
*

View File

@@ -1,3 +1,4 @@
obj-$(CONFIG_MXC_IPU_V3) = mxc_ipu.o
mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o
mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o ipu_calc_stripes_sizes.o

View File

@@ -0,0 +1,374 @@
/*
* Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file ipu_calc_stripes_sizes.c
*
* @brief IPU IC functions
*
* @ingroup IPU
*/
#include <linux/module.h>
#include <linux/ipu.h>
#include <asm/div64.h>
#define BPP_32 0
#define BPP_16 3
#define BPP_8 5
#define BPP_24 1
#define BPP_12 4
#define BPP_18 2
static u64 _do_div(u64 a, u32 b)
{
u64 div;
div = a;
do_div(div, b);
return div;
}
static u32 truncate(u32 up, /* 0: down; else: up */
u64 a, /* must be non-negative */
u32 b)
{
u32 d;
u64 div;
div = _do_div(a, b);
d = b * (div >> 32);
if (up && (a > (((u64)d) << 32)))
return d+b;
else
return d;
}
static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
{/* return input_f */
unsigned int f_calculated = 0;
switch (pfs) {
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
f_calculated = 16;
break;
case IPU_PIX_FMT_NV12:
f_calculated = 8;
break;
default:
f_calculated = 0;
break;
}
if (!f_calculated) {
switch (bpp) {
case BPP_32:
f_calculated = 2;
break;
case BPP_16:
f_calculated = 4;
break;
case BPP_8:
case BPP_24:
f_calculated = 8;
break;
case BPP_12:
f_calculated = 16;
break;
case BPP_18:
f_calculated = 32;
break;
default:
f_calculated = 0;
break;
}
}
return f_calculated;
}
static unsigned int m_calc(unsigned int pfs)
{
unsigned int m_calculated = 0;
switch (pfs) {
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_NV12:
m_calculated = 8;
break;
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
m_calculated = 2;
break;
default:
m_calculated = 1;
break;
}
return m_calculated;
}
/* Stripe parameters calculator */
/**************************************************************************
Notes:
MSW = the maximal width allowed for a stripe
i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
cirr = the maximal inverse resizing ratio for which overlap in the input
is requested; typically cirr~2
equal_stripes:
0: each stripe is allowed to have independent parameters
for maximal image quality
1: the stripes are requested to have identical parameters
(except the base address), for maximal performance
If performance is the top priority (above image quality)
Avoid overlap, by setting CIRR = 0
This will also force effectively identical_stripes = 1
Choose IF & OF that corresponds to the same IOX/SX for both stripes
Choose IFW & OFW such that
IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
The function returns an error status:
0: no error
1: invalid input parameters -> aborted without result
Valid parameters should satisfy the following conditions
IFW <= OFW, otherwise downsizing is required
- which is not supported yet
4 <= IFW,OFW, so some interpolation may be needed even without overlap
IM, OM, IF, OF should not vanish
2*IF <= IFW
so the frame can be split to two equal stripes, even without overlap
2*(OF+IF/irr_opt) <= OFW
so a valid positive INW exists even for equal stripes
OF <= MSW, otherwise, the left stripe cannot be sufficiently large
MSW < OFW, so splitting to stripes is required
OFW <= 2*MSW, so two stripes are sufficient
(this also implies that 2<=MSW)
2: OF is not a multiple of OM - not fully-supported yet
Output is produced but OW is not guaranited to be a multiple of OM
4: OFW reduced to be a multiple of OM
8: CIRR > 1: truncated to 1
Overlap is not supported (and not needed) y for upsizing)
**************************************************************************/
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
/* input frame width;>1 */
unsigned int output_frame_width, /* output frame width; >1 */
const unsigned int maximal_stripe_width,
/* the maximal width allowed for a stripe */
const unsigned long long cirr, /* see above */
const unsigned int equal_stripes, /* see above */
u32 input_pixelformat,/* pixel format after of read channel*/
u32 output_pixelformat,/* pixel format after of write channel*/
struct stripe_param *left,
struct stripe_param *right)
{
const unsigned int irr_frac_bits = 13;
const unsigned long irr_steps = 1 << irr_frac_bits;
const u64 dirr = ((u64)1) << (32 - 2);
/* The maximum relative difference allowed between the irrs */
const u64 cr = ((u64)4) << 32;
/* The importance ratio between the two terms in the cost function below */
unsigned int status;
unsigned int temp;
unsigned int onw_min;
unsigned int inw, onw, inw_best = 0;
/* number of pixels in the left stripe NOT hidden by the right stripe */
u64 irr_opt; /* the optimal inverse resizing ratio */
u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
u64 dinw; /* the misalignment between the stripes */
/* (measured in units of input columns) */
u64 difwl, difwr;
/* The number of input columns not reflected in the output */
/* the resizing ratio used for the right stripe is */
/* left->irr and right->irr respectively */
u64 cost, cost_min;
u64 div; /* result of division */
unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
status = 0;
/* M, F calculations */
/* read back pfs from params */
input_f = f_calc(input_pixelformat, 0, NULL);
input_m = 16;
/* BPP should be used in the out_F calc */
/* Temporarily not used */
/* out_F = F_calc(idmac->pfs, idmac->bpp, NULL); */
output_f = 16;
output_m = m_calc(output_pixelformat);
if ((output_frame_width < input_frame_width) || (input_frame_width < 4)
|| (output_frame_width < 4))
return 1;
irr_opt = _do_div((((u64)(input_frame_width - 1)) << 32),
(output_frame_width - 1));
rr_opt = _do_div((((u64)(output_frame_width - 1)) << 32),
(input_frame_width - 1));
if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
|| (input_frame_width < (2 * input_f))
|| ((((u64)output_frame_width) << 32) <
(2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
|| (maximal_stripe_width < output_f)
|| (output_frame_width <= maximal_stripe_width)
|| ((2 * maximal_stripe_width) < output_frame_width))
return 1;
if (output_f % output_m)
status += 2;
temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
if (temp < output_frame_width) {
output_frame_width = temp;
status += 4;
}
if (equal_stripes) {
if ((irr_opt > cirr) /* overlap in the input is not requested */
&& ((input_frame_width % (input_m << 1)) == 0)
&& ((input_frame_width % (input_f << 1)) == 0)
&& ((output_frame_width % (output_m << 1)) == 0)
&& ((output_frame_width % (output_f << 1)) == 0)) {
/* without overlap */
left->input_width = right->input_width = right->input_column =
input_frame_width >> 1;
left->output_width = right->output_width = right->output_column =
output_frame_width >> 1;
left->input_column = right->input_column = 0;
div = _do_div(((((u64)irr_steps) << 32) *
(right->input_width - 1)), (right->output_width - 1));
left->irr = right->irr = truncate(0, div, 1);
} else { /* with overlap */
onw = truncate(0, (((u64)output_frame_width) << 32) >> 1,
output_f);
inw = truncate(0, onw * irr_opt, input_f);
/* this is the maximal inw which allows the same resizing ratio */
/* in both stripes */
onw = truncate(1, (inw * rr_opt), output_f);
div = _do_div((((u64)(irr_steps * inw)) <<
32), onw);
left->irr = right->irr = truncate(0, div, 1);
left->output_width = right->output_width =
output_frame_width - onw;
/* These are valid assignments for output_width, */
/* assuming output_f is a multiple of output_m */
div = (((u64)(left->output_width-1) * (left->irr)) << 32);
div = (((u64)1) << 32) + _do_div(div, irr_steps);
left->input_width = right->input_width = truncate(1, div, input_m);
div = _do_div((((u64)((right->output_width - 1) * right->irr)) <<
32), irr_steps);
difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
div = _do_div((difwr + (((u64)input_f) << 32)), 2);
left->input_column = truncate(0, div, input_f);
/* This splits the truncated input columns evenly */
/* between the left and right margins */
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
}
} else { /* independent stripes */
onw_min = output_frame_width - maximal_stripe_width;
/* onw is a multiple of output_f, in the range */
/* [max(output_f,output_frame_width-maximal_stripe_width),*/
/*min(output_frame_width-2,maximal_stripe_width)] */
/* definitely beyond the cost of any valid setting */
cost_min = (((u64)input_frame_width) << 32) + cr;
onw = truncate(0, ((u64)maximal_stripe_width), output_f);
if (output_frame_width - onw == 1)
onw -= output_f; /* => onw and output_frame_width-1-onw are positive */
inw = truncate(0, onw * irr_opt, input_f);
/* this is the maximal inw which allows the same resizing ratio */
/* in both stripes */
onw = truncate(1, inw * rr_opt, output_f);
do {
div = _do_div((((u64)(irr_steps * inw)) << 32), onw);
left->irr = truncate(0, div, 1);
div = _do_div((((u64)(onw * left->irr)) << 32),
irr_steps);
dinw = (((u64)inw) << 32) - div;
div = _do_div((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
32), irr_steps);
difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
cost = difwl + (((u64)(cr * dinw)) >> 32);
if (cost < cost_min) {
inw_best = inw;
cost_min = cost;
}
inw -= input_f;
onw = truncate(1, inw * rr_opt, output_f);
/* This is the minimal onw which allows the same resizing ratio */
/* in both stripes */
} while (onw >= onw_min);
inw = inw_best;
onw = truncate(1, inw * rr_opt, output_f);
div = _do_div((((u64)(irr_steps * inw)) << 32), onw);
left->irr = truncate(0, div, 1);
left->output_width = onw;
right->output_width = output_frame_width - onw;
/* These are valid assignments for output_width, */
/* assuming output_f is a multiple of output_m */
left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
32, input_m);
div = _do_div((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
32), (right->output_width - 1));
right->irr = truncate(0, div, 1);
temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
if (temp < right->irr)
right->irr = temp;
div = _do_div(((u64)((right->output_width - 1) * right->irr) <<
32), irr_steps);
difwr = (u64)(input_frame_width - 1 - inw) - div;
div = _do_div((difwr + (((u64)input_f) << 32)), 2);
left->input_column = truncate(0, div, input_f);
/* This splits the truncated input columns evenly */
/* between the left and right margins */
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
}
return status;
}
EXPORT_SYMBOL(ipu_calc_stripes_sizes);

View File

@@ -947,8 +947,9 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
} else if (_ipu_is_dmfc_chan(dma_chan))
_ipu_dmfc_set_wait4eot(dma_chan, width);
if (_ipu_chan_is_interlaced(channel))
if (_ipu_chan_is_interlaced(channel)) {
_ipu_ch_param_set_interlaced_scan(dma_chan);
}
if (_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan)) {
burst_size = _ipu_ch_param_get_burst_size(dma_chan);
@@ -1031,6 +1032,71 @@ int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
}
EXPORT_SYMBOL(ipu_update_channel_buffer);
/*!
* This function is called to initialize a buffer for logical IPU channel.
*
* @param channel Input parameter for the logical channel ID.
*
* @param type Input parameter which buffer to initialize.
*
* @param pixel_fmt Input parameter for pixel format of buffer.
* Pixel format is a FOURCC ASCII code.
*
* @param width Input parameter for width of buffer in pixels.
*
* @param height Input parameter for height of buffer in pixels.
*
* @param stride Input parameter for stride length of buffer
* in pixels.
*
* @param u predefined private u offset for additional cropping,
* zero if not used.
*
* @param v predefined private v offset for additional cropping,
* zero if not used.
*
* @param vertical_offset vertical offset for Y coordinate
* in the existed frame
*
*
* @param horizontal_offset horizontal offset for X coordinate
* in the existed frame
*
*
* @return Returns 0 on success or negative error code on fail
* This function will fail if any buffer is set to ready.
*/
int32_t ipu_update_channel_offset(ipu_channel_t channel, ipu_buffer_t type,
uint32_t pixel_fmt,
uint16_t width, uint16_t height,
uint32_t stride,
uint32_t u, uint32_t v,
uint32_t vertical_offset, uint32_t horizontal_offset)
{
int ret = 0;
unsigned long lock_flags;
uint32_t dma_chan = channel_2_dma(channel, type);
if (dma_chan == IDMA_CHAN_INVALID)
return -EINVAL;
spin_lock_irqsave(&ipu_lock, lock_flags);
if ((__raw_readl(IPU_CHA_BUF0_RDY(dma_chan)) & idma_mask(dma_chan)) ||
(__raw_readl(IPU_CHA_BUF0_RDY(dma_chan)) & idma_mask(dma_chan)))
ret = -EACCES;
else
_ipu_ch_offset_update(dma_chan, pixel_fmt, width, height, stride,
u, v, 0, vertical_offset, horizontal_offset);
spin_unlock_irqrestore(&ipu_lock, lock_flags);
return ret;
}
EXPORT_SYMBOL(ipu_update_channel_offset);
/*!
* This function is called to set a channel's buffer as ready.
*

View File

@@ -416,10 +416,14 @@ void _ipu_ic_init_pp(ipu_channel_params_t *params)
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
/* Setup horizontal resizing */
_calc_resize_coeffs(params->mem_pp_mem.in_width,
params->mem_pp_mem.out_width,
&resizeCoeff, &downsizeCoeff);
reg |= (downsizeCoeff << 14) | resizeCoeff;
/* Upadeted for IC split case */
if (!(params->mem_pp_mem.out_resize_ratio)) {
_calc_resize_coeffs(params->mem_pp_mem.in_width,
params->mem_pp_mem.out_width,
&resizeCoeff, &downsizeCoeff);
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else
reg |= params->mem_pp_mem.out_resize_ratio;
__raw_writel(reg, IC_PP_RSC);

View File

@@ -383,9 +383,112 @@ static inline void _ipu_ch_param_set_high_priority(uint32_t ch)
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 93, 2, 1);
};
/* IDMAC U/V offset changing support */
/* U and V input is not affected, */
/* the update is done by new calculation according to */
/* vertical_offset and horizontal_offset */
static inline void _ipu_ch_offset_update(int ch,
uint32_t pixel_fmt,
uint32_t width,
uint32_t height,
uint32_t stride,
uint32_t u,
uint32_t v,
uint32_t uv_stride,
uint32_t vertical_offset,
uint32_t horizontal_offset)
{
uint32_t u_offset = 0;
uint32_t v_offset = 0;
uint32_t u_fix = 0;
uint32_t v_fix = 0;
switch (pixel_fmt) {
case IPU_PIX_FMT_GENERIC:
case IPU_PIX_FMT_GENERIC_32:
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_YUV444:
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_RGB32:
case IPU_PIX_FMT_ABGR32:
case IPU_PIX_FMT_UYVY:
case IPU_PIX_FMT_YUYV:
break;
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
u_fix = u + (uv_stride * vertical_offset / 2) + horizontal_offset / 4;
v_fix = v + (uv_stride * vertical_offset / 2) + horizontal_offset / 4;
u_offset = (u == 0) ? stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset / 2) +
horizontal_offset / 2 : u_fix;
v_offset = (v == 0) ? u_offset + (uv_stride * height / 2) : v_fix;
break;
case IPU_PIX_FMT_YVU422P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
u_fix = u + (uv_stride * vertical_offset) + horizontal_offset / 2;
v_fix = v + (uv_stride * vertical_offset) + horizontal_offset / 2;
v_offset = (v == 0) ? stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset) +
horizontal_offset / 2 : v_fix;
u_offset = (u == 0) ? v_offset + uv_stride * height : u_fix;
break;
case IPU_PIX_FMT_YUV422P:
if (uv_stride < stride / 2)
uv_stride = stride / 2;
u_fix = u + (uv_stride * vertical_offset) + horizontal_offset / 2;
v_fix = v + (uv_stride * vertical_offset) + horizontal_offset / 2;
u_offset = (u == 0) ? stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset) +
horizontal_offset / 2 : u_fix;
v_offset = (v == 0) ? u_offset + uv_stride * height : v_fix;
break;
case IPU_PIX_FMT_NV12:
uv_stride = stride;
u_fix = u + (uv_stride * vertical_offset) + horizontal_offset;
u_offset = (u == 0) ? stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
(uv_stride * vertical_offset) +
horizontal_offset : u_fix;
break;
default:
dev_err(g_ipu_dev, "mxc ipu: unimplemented pixel format\n");
break;
}
if (u_fix > u_offset)
u_offset = u_fix;
if (v_fix > v_offset)
v_offset = v_fix;
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 46, 22, u_offset / 8);
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 68, 22, v_offset / 8);
};
static inline void _ipu_ch_params_set_alpha_width(uint32_t ch, int alpha_width)
{
ipu_ch_param_set_field(ipu_ch_param_addr(ch), 1, 125, 3, alpha_width - 1);
}
};
#endif

View File

@@ -393,6 +393,7 @@ typedef union {
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
uint32_t out_resize_ratio;
} mem_pp_mem;
struct {
uint32_t temp;
@@ -877,6 +878,13 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
uint32_t bufNum, dma_addr_t phyaddr);
int32_t ipu_update_channel_offset(ipu_channel_t channel, ipu_buffer_t type,
uint32_t pixel_fmt,
uint16_t width, uint16_t height,
uint32_t stride,
uint32_t u, uint32_t v,
uint32_t vertical_offset, uint32_t horizontal_offset);
int32_t ipu_select_buffer(ipu_channel_t channel,
ipu_buffer_t type, uint32_t bufNum);
int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum);
@@ -1198,4 +1206,30 @@ typedef struct _ipu_mem_info {
#define IPU_FREE_MEM _IOW('I', 0x25, ipu_mem_info)
#define IPU_IS_CHAN_BUSY _IOW('I', 0x26, ipu_channel_t)
/* two stripe calculations */
struct stripe_param{
unsigned int input_width; /* width of the input stripe */
unsigned int output_width; /* width of the output stripe */
unsigned int input_column; /* the first column on the input stripe */
unsigned int output_column; /* the first column on the output stripe */
unsigned int idr;
/* inverse downisizing ratio parameter; expressed as a power of 2 */
unsigned int irr;
/* inverse resizing ratio parameter; expressed as a multiple of 2^-13 */
};
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
unsigned int output_frame_width,
const unsigned int maximal_stripe_width,
const unsigned long long cirr,
const unsigned int equal_stripes,
u32 input_pixelformat,
u32 output_pixelformat,
struct stripe_param *left,
struct stripe_param *right);
#endif