From: Oliver Brown Date: Tue, 19 Nov 2013 15:49:53 +0000 (-0600) Subject: ENGR00272541 IPUv3 IC: Split Downsizing overflow for size greater than 1024 X-Git-Tag: KARO-TX6-2014-08-21~1^2~131 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=e59f3a5258cf1df87f5c5b183cfc038bec77a1a2;p=karo-tx-linux.git 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 --- diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c index 4458996c603e..7c4181dd572f 100644 --- a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c +++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c @@ -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 72a9905d5bea..d0127327f197 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -859,7 +859,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; @@ -902,7 +904,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 f2d8e537b8db..2da79dfed287 100644 --- a/drivers/mxc/ipu3/ipu_ic.c +++ b/drivers/mxc/ipu3/ipu_ic.c @@ -243,9 +243,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); @@ -260,10 +258,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); @@ -388,9 +383,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, @@ -406,10 +399,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); @@ -487,9 +477,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); @@ -505,10 +493,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);