Hi Yong, On Tue, Jul 18, 2017 at 10:13:40PM -0500, Yong Zhi wrote: > A collection of routines that are mainly responsible > to calculate the acc parameters. > > Signed-off-by: Yong Zhi <yong.zhi@xxxxxxxxx> > --- > drivers/media/pci/intel/ipu3/ipu3-css-params.c | 3114 ++++++++++++++++++++++++ > drivers/media/pci/intel/ipu3/ipu3-css-params.h | 105 + > drivers/media/pci/intel/ipu3/ipu3-css.h | 92 + > 3 files changed, 3311 insertions(+) > create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-params.c > create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-params.h > > diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-params.c b/drivers/media/pci/intel/ipu3/ipu3-css-params.c > new file mode 100644 > index 0000000..4b600bc > --- /dev/null > +++ b/drivers/media/pci/intel/ipu3/ipu3-css-params.c > @@ -0,0 +1,3114 @@ > +/* > + * Copyright (c) 2017 Intel Corporation. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License version > + * 2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#include <linux/device.h> > +#include <linux/dma-mapping.h> > + > +#include "ipu3-abi.h" > +#include "ipu3-css.h" > +#include "ipu3-css-fw.h" > +#include "ipu3-css-params.h" > +#include "ipu3-tables.h" > + > +static unsigned int ipu3_css_scaler_get_exp(unsigned int counter, > + unsigned int divider) > +{ > + int i = fls(divider) - fls(counter); > + > + if (i <= 0) > + return 0; > + > + if (divider >> i < counter) > + i = i - 1; i--; > + > + return i; > +} > + > +/* Set up the CSS scaler look up table */ > +static void ipu3_css_scaler_setup_lut(unsigned int taps, > + unsigned int input_width, > + unsigned int output_width, > + int phase_step_correction, > + const int *coeffs, > + unsigned int coeffs_size, > + s8 coeff_lut[IMGU_SCALER_PHASES * > + IMGU_SCALER_FILTER_TAPS], > + struct ipu3_css_scaler_info *info) > +{ > + int tap; > + int phase; > + int exponent = ipu3_css_scaler_get_exp(output_width, input_width); > + int mantissa = (1 << exponent) * output_width; > + unsigned int phase_step = 0; > + int phase_sum_left = 0; > + int phase_sum_right = 0; > + > + for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) { > + for (tap = 0; tap < taps; tap++) { > + /* flip table to for convolution reverse indexing */ > + s64 coeff = coeffs[coeffs_size - > + ((tap * (coeffs_size / taps)) + > + phase) - 1]; > + coeff *= mantissa; > + coeff /= input_width; Please use do_div() so this will compile on 32-bit machines. > + > + /* Add +"0.5" */ > + coeff += 1 << (IMGU_SCALER_COEFF_BITS - 1); > + coeff >>= IMGU_SCALER_COEFF_BITS; > + > + coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap] = > + coeff; > + } > + } > + > + phase_step = IMGU_SCALER_PHASES * > + (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF) > + * output_width / input_width; > + phase_step += phase_step_correction; > + phase_sum_left = (taps / 2 * IMGU_SCALER_PHASES * > + (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) > + - (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1)); > + phase_sum_right = (taps / 2 * IMGU_SCALER_PHASES * > + (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) > + + (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1)); > + > + info->exp_shift = IMGU_SCALER_MAX_EXPONENT_SHIFT - exponent; > + info->pad_left = (phase_sum_left % phase_step == 0) ? > + phase_sum_left / phase_step - 1 : phase_sum_left / phase_step; > + info->pad_right = (phase_sum_right % phase_step == 0) ? > + phase_sum_right / phase_step - 1 : phase_sum_right / phase_step; > + info->phase_init = phase_sum_left - phase_step * info->pad_left; > + info->phase_step = phase_step; > + info->crop_left = taps - 1; > + info->crop_top = taps - 1; > +} > + > +/* > + * Calculates the exact output image width/height, based on phase_step setting > + * (must be perfectly aligned with hardware). > + */ > +static unsigned int ipu3_css_scaler_calc_scaled_output(unsigned int input, > + struct ipu3_css_scaler_info *info) > +{ > + unsigned int arg1 = input * info->phase_step + > + (1 - IMGU_SCALER_TAPS_Y / 2) * > + IMGU_SCALER_FIR_PHASES - IMGU_SCALER_FIR_PHASES > + / (2 * IMGU_SCALER_PHASES); > + unsigned int arg2 = ((IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES > + + IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES)) > + * IMGU_SCALER_FIR_PHASES + info->phase_step / 2; > + > + return ((arg1 + (arg2 - IMGU_SCALER_FIR_PHASES * info->phase_step) > + / IMGU_SCALER_FIR_PHASES) / (2 * IMGU_SCALER_FIR_PHASES)) * 2; > +} > + > +/* > + * Calculate the output width and height, given the luma > + * and chroma details of a scaler > + */ > +static int ipu3_css_scaler_calc(u32 input_width, u32 input_height, > + u32 target_width, u32 target_height, > + struct ipu3_uapi_osys_config *cfg, > + struct ipu3_css_scaler_info *info_luma, > + struct ipu3_css_scaler_info *info_chroma, > + unsigned int *output_width, > + unsigned int *output_height) > +{ > + u32 out_width = target_width; > + u32 out_height = target_height; > + unsigned int height_alignment = 2; > + int phase_step_correction = -1; > + > + /* > + * Calculate scaled output width. If the horizontal and vertical scaling > + * factor is different, then choose the biggest and crop off excess > + * lines or columns after formatting. > + */ > + if (target_height * input_width > target_width * input_height) > + target_width = DIV_ROUND_UP(target_height * input_width, > + input_height); > + > + memset(&cfg->scaler_coeffs_chroma, 0, > + sizeof(cfg->scaler_coeffs_chroma)); > + memset(&cfg->scaler_coeffs_luma, 0, sizeof(*cfg->scaler_coeffs_luma)); > + do { > + phase_step_correction++; > + > + ipu3_css_scaler_setup_lut(IMGU_SCALER_TAPS_Y, > + input_width, target_width, > + phase_step_correction, > + ipu3_css_downscale_4taps, > + IMGU_SCALER_DOWNSCALE_4TAPS_LEN, > + cfg->scaler_coeffs_luma, info_luma); > + > + ipu3_css_scaler_setup_lut(IMGU_SCALER_TAPS_UV, > + input_width, target_width, > + phase_step_correction, > + ipu3_css_downscale_2taps, > + IMGU_SCALER_DOWNSCALE_2TAPS_LEN, > + cfg->scaler_coeffs_chroma, > + info_chroma); > + > + out_width = ipu3_css_scaler_calc_scaled_output(input_width, > + info_luma); > + out_height = ipu3_css_scaler_calc_scaled_output(input_height, > + info_luma); > + } while ((out_width < target_width || out_height < target_height > + || !IS_ALIGNED(out_height, height_alignment)) > + && phase_step_correction <= 5); > + > + *output_width = out_width; > + *output_height = out_height; > + > + return 0; > +} > + > +/********************** Osys routines for scaler*****************************/ > + > +/* FIXME: > + * The OSYS formats could be added nicely into table > + * "ipu3_css_formats", avoiding the "switch...case" here. > + */ I think the switch below is entirely reasonable, no need for such a comment. > +static void ipu3_css_osys_set_format(enum imgu_abi_frame_format host_format, > + unsigned int *osys_format, > + unsigned int *osys_tiling) > +{ > + *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420; > + *osys_tiling = IMGU_ABI_OSYS_TILING_NONE; > + > + switch (host_format) { > + case IMGU_ABI_FRAME_FORMAT_YUV420: > + *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420; > + break; > + case IMGU_ABI_FRAME_FORMAT_YV12: > + *osys_format = IMGU_ABI_OSYS_FORMAT_YV12; > + break; > + case IMGU_ABI_FRAME_FORMAT_NV12: > + *osys_format = IMGU_ABI_OSYS_FORMAT_NV12; > + break; > + case IMGU_ABI_FRAME_FORMAT_NV16: > + *osys_format = IMGU_ABI_OSYS_FORMAT_NV16; > + break; > + case IMGU_ABI_FRAME_FORMAT_NV21: > + *osys_format = IMGU_ABI_OSYS_FORMAT_NV21; > + break; > + case IMGU_ABI_FRAME_FORMAT_NV12_TILEY: > + *osys_format = IMGU_ABI_OSYS_FORMAT_NV12; > + *osys_tiling = IMGU_ABI_OSYS_TILING_Y; > + break; > + default: > + /* For now, assume use default values */ > + break; > + } > +} -- Sakari Ailus e-mail: sakari.ailus@xxxxxx