summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Brown <oliver.brown@freescale.com>2014-08-01 12:27:52 -0500
committerPeng Fushi <fushi.peng@freescale.com>2014-08-28 16:51:40 +0800
commitb9cadab6663c0d70b3f75fa6c5b4291641e0a5a0 (patch)
treed1b92f0bf57e55a84b7eb53e215a5d775389c67b
parentb59b9e418461555d174ce78a9d6737c33e000952 (diff)
ENGR00272541 IPUv3 IC: Split Downsizing overflow for size greater than 1024
For downscaling, it is possible that downscaler output is greater than 1024. Added a function, calc_split_resize_coeffs, based upon _calc_resize_coeffs to calculate resizing and downscaling coefficients. In ipu_ic.c, checks for the range of *_resize_ratio are no longer needed. Non split cases will always have *_resize_ratio of zero. In ipu_device, additional checks are needed to check for an error from ipu_calc_stripes_sizes if calc_split_resize_coeffs fails. Signed-off-by: Oliver Brown <oliver.brown@freescale.com>
-rw-r--r--drivers/mxc/ipu3/ipu_calc_stripes_sizes.c82
-rw-r--r--drivers/mxc/ipu3/ipu_device.c8
-rw-r--r--drivers/mxc/ipu3/ipu_ic.c27
3 files changed, 92 insertions, 25 deletions
diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
index 3a27195bbc3d..e0ad57bb4ee8 100644
--- a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
+++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -125,6 +125,57 @@ static unsigned int m_calc(unsigned int pfs)
return m_calculated;
}
+static int calc_split_resize_coeffs(unsigned int inSize, unsigned int outSize,
+ unsigned int *resizeCoeff,
+ unsigned int *downsizeCoeff)
+{
+ uint32_t tempSize;
+ uint32_t tempDownsize;
+
+ if (inSize > 4096) {
+ pr_debug("IC input size(%d) cannot exceed 4096\n",
+ inSize);
+ return -EINVAL;
+ }
+
+ if (outSize > 1024) {
+ pr_debug("IC output size(%d) cannot exceed 1024\n",
+ outSize);
+ return -EINVAL;
+ }
+
+ if ((outSize << 3) < inSize) {
+ pr_debug("IC cannot downsize more than 8:1\n");
+ return -EINVAL;
+ }
+
+ /* Compute downsizing coefficient */
+ /* Output of downsizing unit cannot be more than 1024 */
+ tempDownsize = 0;
+ tempSize = inSize;
+ while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
+ (tempDownsize < 2)) {
+ tempSize >>= 1;
+ tempDownsize++;
+ }
+ *downsizeCoeff = tempDownsize;
+
+ /* compute resizing coefficient using the following equation:
+ resizeCoeff = M*(SI -1)/(SO - 1)
+ where M = 2^13, SI - input size, SO - output size */
+ *resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
+ if (*resizeCoeff >= 16384L) {
+ pr_debug("Overflow on IC resize coefficient.\n");
+ return -EINVAL;
+ }
+
+ pr_debug("resizing from %u -> %u pixels, "
+ "downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
+ *downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
+ ((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
+
+ return 0;
+}
/* Stripe parameters calculator */
/**************************************************************************
@@ -202,6 +253,8 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
u64 div; /* result of division */
unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
+ unsigned int resize_coeff;
+ unsigned int downsize_coeff;
status = 0;
@@ -292,7 +345,16 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
left->output_column = 0;
right->output_column = onw;
}
- } else { /* independent stripes */
+ if (left->input_width > left->output_width) {
+ if (calc_split_resize_coeffs(left->input_width,
+ left->output_width,
+ &resize_coeff,
+ &downsize_coeff) < 0)
+ return -EINVAL;
+ left->irr = right->irr =
+ (downsize_coeff << 14) | resize_coeff;
+ }
+ } 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),*/
@@ -363,6 +425,22 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
right->input_column = left->input_column + inw;
left->output_column = 0;
right->output_column = onw;
+ if (left->input_width > left->output_width) {
+ if (calc_split_resize_coeffs(left->input_width,
+ left->output_width,
+ &resize_coeff,
+ &downsize_coeff) < 0)
+ return -EINVAL;
+ left->irr = (downsize_coeff << 14) | resize_coeff;
+ }
+ if (right->input_width > right->output_width) {
+ if (calc_split_resize_coeffs(right->input_width,
+ right->output_width,
+ &resize_coeff,
+ &downsize_coeff) < 0)
+ return -EINVAL;
+ right->irr = (downsize_coeff << 14) | resize_coeff;
+ }
}
return status;
}
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
index 0506038b0d4a..21378e27150a 100644
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -858,7 +858,9 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
t->output.format,
&left_stripe,
&right_stripe);
- if (ret)
+ if (ret < 0)
+ return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+ else if (ret)
dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
t->task_no, ret);
t->set.sp_setting.iw = left_stripe.input_width;
@@ -901,7 +903,9 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
t->output.format,
&up_stripe,
&down_stripe);
- if (ret)
+ if (ret < 0)
+ return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+ else if (ret)
dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
t->task_no, ret);
t->set.sp_setting.ih = up_stripe.input_width;
diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c
index 7437c7461512..b5df9ee675a6 100644
--- a/drivers/mxc/ipu3/ipu_ic.c
+++ b/drivers/mxc/ipu3/ipu_ic.c
@@ -244,9 +244,7 @@ int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
int ret = 0;
/* Setup vertical resizing */
- if (!(params->mem_prp_vf_mem.outv_resize_ratio) ||
- (params->mem_prp_vf_mem.outv_resize_ratio >=
- IC_RSZ_MAX_RESIZE_RATIO)) {
+ if (!params->mem_prp_vf_mem.outv_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
params->mem_prp_vf_mem.out_height,
&resizeCoeff, &downsizeCoeff);
@@ -261,10 +259,7 @@ int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
/* Setup horizontal resizing */
- /* Upadeted for IC split case */
- if (!(params->mem_prp_vf_mem.outh_resize_ratio) ||
- (params->mem_prp_vf_mem.outh_resize_ratio >=
- IC_RSZ_MAX_RESIZE_RATIO)) {
+ if (!params->mem_prp_vf_mem.outh_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
params->mem_prp_vf_mem.out_width,
&resizeCoeff, &downsizeCoeff);
@@ -389,9 +384,7 @@ int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
int ret = 0;
/* Setup vertical resizing */
- if (!(params->mem_prp_enc_mem.outv_resize_ratio) ||
- (params->mem_prp_enc_mem.outv_resize_ratio >=
- IC_RSZ_MAX_RESIZE_RATIO)) {
+ if (!params->mem_prp_enc_mem.outv_resize_ratio) {
ret = _calc_resize_coeffs(ipu,
params->mem_prp_enc_mem.in_height,
params->mem_prp_enc_mem.out_height,
@@ -407,10 +400,7 @@ int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
/* Setup horizontal resizing */
- /* Upadeted for IC split case */
- if (!(params->mem_prp_enc_mem.outh_resize_ratio) ||
- (params->mem_prp_enc_mem.outh_resize_ratio >=
- IC_RSZ_MAX_RESIZE_RATIO)) {
+ if (!params->mem_prp_enc_mem.outh_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
params->mem_prp_enc_mem.out_width,
&resizeCoeff, &downsizeCoeff);
@@ -488,9 +478,7 @@ int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
int ret = 0;
/* Setup vertical resizing */
- if (!(params->mem_pp_mem.outv_resize_ratio) ||
- (params->mem_pp_mem.outv_resize_ratio >=
- IC_RSZ_MAX_RESIZE_RATIO)) {
+ if (!params->mem_pp_mem.outv_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
params->mem_pp_mem.out_height,
&resizeCoeff, &downsizeCoeff);
@@ -506,10 +494,7 @@ int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
}
/* Setup horizontal resizing */
- /* Upadeted for IC split case */
- if (!(params->mem_pp_mem.outh_resize_ratio) ||
- (params->mem_pp_mem.outh_resize_ratio >=
- IC_RSZ_MAX_RESIZE_RATIO)) {
+ if (!params->mem_pp_mem.outh_resize_ratio) {
ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
params->mem_pp_mem.out_width,
&resizeCoeff, &downsizeCoeff);