Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2018 Intel Corporation
0003 
0004 #include <linux/device.h>
0005 
0006 #include "ipu3-css.h"
0007 #include "ipu3-css-fw.h"
0008 #include "ipu3-tables.h"
0009 #include "ipu3-css-params.h"
0010 
0011 #define DIV_ROUND_CLOSEST_DOWN(a, b)    (((a) + ((b) / 2) - 1) / (b))
0012 #define roundclosest_down(a, b)     (DIV_ROUND_CLOSEST_DOWN(a, b) * (b))
0013 
0014 #define IPU3_UAPI_ANR_MAX_RESET     ((1 << 12) - 1)
0015 #define IPU3_UAPI_ANR_MIN_RESET     (((-1) << 12) + 1)
0016 
0017 struct imgu_css_scaler_info {
0018     unsigned int phase_step;    /* Same for luma/chroma */
0019     int exp_shift;
0020 
0021     unsigned int phase_init;    /* luma/chroma dependent */
0022     int pad_left;
0023     int pad_right;
0024     int crop_left;
0025     int crop_top;
0026 };
0027 
0028 static unsigned int imgu_css_scaler_get_exp(unsigned int counter,
0029                         unsigned int divider)
0030 {
0031     int i = fls(divider) - fls(counter);
0032 
0033     if (i <= 0)
0034         return 0;
0035 
0036     if (divider >> i < counter)
0037         i = i - 1;
0038 
0039     return i;
0040 }
0041 
0042 /* Set up the CSS scaler look up table */
0043 static void
0044 imgu_css_scaler_setup_lut(unsigned int taps, unsigned int input_width,
0045               unsigned int output_width, int phase_step_correction,
0046               const int *coeffs, unsigned int coeffs_size,
0047               s8 coeff_lut[], struct imgu_css_scaler_info *info)
0048 {
0049     int tap, phase, phase_sum_left, phase_sum_right;
0050     int exponent = imgu_css_scaler_get_exp(output_width, input_width);
0051     int mantissa = (1 << exponent) * output_width;
0052     unsigned int phase_step, phase_taps;
0053 
0054     if (input_width == output_width) {
0055         for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
0056             phase_taps = phase * IMGU_SCALER_FILTER_TAPS;
0057             for (tap = 0; tap < taps; tap++)
0058                 coeff_lut[phase_taps + tap] = 0;
0059         }
0060 
0061         info->phase_step = IMGU_SCALER_PHASES *
0062             (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF);
0063         info->exp_shift = 0;
0064         info->pad_left = 0;
0065         info->pad_right = 0;
0066         info->phase_init = 0;
0067         info->crop_left = 0;
0068         info->crop_top = 0;
0069         return;
0070     }
0071 
0072     for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
0073         phase_taps = phase * IMGU_SCALER_FILTER_TAPS;
0074         for (tap = 0; tap < taps; tap++) {
0075             /* flip table to for convolution reverse indexing */
0076             s64 coeff = coeffs[coeffs_size -
0077                 ((tap * (coeffs_size / taps)) + phase) - 1];
0078             coeff *= mantissa;
0079             coeff = div64_long(coeff, input_width);
0080 
0081             /* Add +"0.5" */
0082             coeff += 1 << (IMGU_SCALER_COEFF_BITS - 1);
0083             coeff >>= IMGU_SCALER_COEFF_BITS;
0084             coeff_lut[phase_taps + tap] = coeff;
0085         }
0086     }
0087 
0088     phase_step = IMGU_SCALER_PHASES *
0089             (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF) *
0090             output_width / input_width;
0091     phase_step += phase_step_correction;
0092     phase_sum_left = (taps / 2 * IMGU_SCALER_PHASES *
0093             (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) -
0094             (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
0095     phase_sum_right = (taps / 2 * IMGU_SCALER_PHASES *
0096             (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) +
0097             (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
0098 
0099     info->exp_shift = IMGU_SCALER_MAX_EXPONENT_SHIFT - exponent;
0100     info->pad_left = (phase_sum_left % phase_step == 0) ?
0101         phase_sum_left / phase_step - 1 : phase_sum_left / phase_step;
0102     info->pad_right = (phase_sum_right % phase_step == 0) ?
0103         phase_sum_right / phase_step - 1 : phase_sum_right / phase_step;
0104     info->phase_init = phase_sum_left - phase_step * info->pad_left;
0105     info->phase_step = phase_step;
0106     info->crop_left = taps - 1;
0107     info->crop_top = taps - 1;
0108 }
0109 
0110 /*
0111  * Calculates the exact output image width/height, based on phase_step setting
0112  * (must be perfectly aligned with hardware).
0113  */
0114 static unsigned int
0115 imgu_css_scaler_calc_scaled_output(unsigned int input,
0116                    struct imgu_css_scaler_info *info)
0117 {
0118     unsigned int arg1 = input * info->phase_step +
0119             (1 - IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES -
0120             IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES);
0121     unsigned int arg2 = ((IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES +
0122             IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES)) *
0123             IMGU_SCALER_FIR_PHASES + info->phase_step / 2;
0124 
0125     return ((arg1 + (arg2 - IMGU_SCALER_FIR_PHASES * info->phase_step) /
0126         IMGU_SCALER_FIR_PHASES) / (2 * IMGU_SCALER_FIR_PHASES)) * 2;
0127 }
0128 
0129 /*
0130  * Calculate the output width and height, given the luma
0131  * and chroma details of a scaler
0132  */
0133 static void
0134 imgu_css_scaler_calc(u32 input_width, u32 input_height, u32 target_width,
0135              u32 target_height, struct imgu_abi_osys_config *cfg,
0136              struct imgu_css_scaler_info *info_luma,
0137              struct imgu_css_scaler_info *info_chroma,
0138              unsigned int *output_width, unsigned int *output_height,
0139              unsigned int *procmode)
0140 {
0141     u32 out_width = target_width;
0142     u32 out_height = target_height;
0143     const unsigned int height_alignment = 2;
0144     int phase_step_correction = -1;
0145 
0146     /*
0147      * Calculate scaled output width. If the horizontal and vertical scaling
0148      * factor is different, then choose the biggest and crop off excess
0149      * lines or columns after formatting.
0150      */
0151     if (target_height * input_width > target_width * input_height)
0152         target_width = DIV_ROUND_UP(target_height * input_width,
0153                         input_height);
0154 
0155     if (input_width == target_width)
0156         *procmode = IMGU_ABI_OSYS_PROCMODE_BYPASS;
0157     else
0158         *procmode = IMGU_ABI_OSYS_PROCMODE_DOWNSCALE;
0159 
0160     memset(&cfg->scaler_coeffs_chroma, 0,
0161            sizeof(cfg->scaler_coeffs_chroma));
0162     memset(&cfg->scaler_coeffs_luma, 0, sizeof(cfg->scaler_coeffs_luma));
0163     do {
0164         phase_step_correction++;
0165 
0166         imgu_css_scaler_setup_lut(IMGU_SCALER_TAPS_Y,
0167                       input_width, target_width,
0168                       phase_step_correction,
0169                       imgu_css_downscale_4taps,
0170                       IMGU_SCALER_DOWNSCALE_4TAPS_LEN,
0171                       cfg->scaler_coeffs_luma, info_luma);
0172 
0173         imgu_css_scaler_setup_lut(IMGU_SCALER_TAPS_UV,
0174                       input_width, target_width,
0175                       phase_step_correction,
0176                       imgu_css_downscale_2taps,
0177                       IMGU_SCALER_DOWNSCALE_2TAPS_LEN,
0178                       cfg->scaler_coeffs_chroma,
0179                       info_chroma);
0180 
0181         out_width = imgu_css_scaler_calc_scaled_output(input_width,
0182                                    info_luma);
0183         out_height = imgu_css_scaler_calc_scaled_output(input_height,
0184                                 info_luma);
0185     } while ((out_width < target_width || out_height < target_height ||
0186          !IS_ALIGNED(out_height, height_alignment)) &&
0187          phase_step_correction <= 5);
0188 
0189     *output_width = out_width;
0190     *output_height = out_height;
0191 }
0192 
0193 /********************** Osys routines for scaler****************************/
0194 
0195 static void imgu_css_osys_set_format(enum imgu_abi_frame_format host_format,
0196                      unsigned int *osys_format,
0197                      unsigned int *osys_tiling)
0198 {
0199     *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
0200     *osys_tiling = IMGU_ABI_OSYS_TILING_NONE;
0201 
0202     switch (host_format) {
0203     case IMGU_ABI_FRAME_FORMAT_YUV420:
0204         *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
0205         break;
0206     case IMGU_ABI_FRAME_FORMAT_YV12:
0207         *osys_format = IMGU_ABI_OSYS_FORMAT_YV12;
0208         break;
0209     case IMGU_ABI_FRAME_FORMAT_NV12:
0210         *osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
0211         break;
0212     case IMGU_ABI_FRAME_FORMAT_NV16:
0213         *osys_format = IMGU_ABI_OSYS_FORMAT_NV16;
0214         break;
0215     case IMGU_ABI_FRAME_FORMAT_NV21:
0216         *osys_format = IMGU_ABI_OSYS_FORMAT_NV21;
0217         break;
0218     case IMGU_ABI_FRAME_FORMAT_NV12_TILEY:
0219         *osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
0220         *osys_tiling = IMGU_ABI_OSYS_TILING_Y;
0221         break;
0222     default:
0223         /* For now, assume use default values */
0224         break;
0225     }
0226 }
0227 
0228 /*
0229  * Function calculates input frame stripe offset, based
0230  * on output frame stripe offset and filter parameters.
0231  */
0232 static int imgu_css_osys_calc_stripe_offset(int stripe_offset_out,
0233                         int fir_phases, int phase_init,
0234                         int phase_step, int pad_left)
0235 {
0236     int stripe_offset_inp = stripe_offset_out * fir_phases -
0237                 pad_left * phase_step;
0238 
0239     return DIV_ROUND_UP(stripe_offset_inp - phase_init, phase_step);
0240 }
0241 
0242 /*
0243  * Calculate input frame phase, given the output frame
0244  * stripe offset and filter parameters
0245  */
0246 static int imgu_css_osys_calc_stripe_phase_init(int stripe_offset_out,
0247                         int fir_phases, int phase_init,
0248                         int phase_step, int pad_left)
0249 {
0250     int stripe_offset_inp =
0251         imgu_css_osys_calc_stripe_offset(stripe_offset_out,
0252                          fir_phases, phase_init,
0253                          phase_step, pad_left);
0254 
0255     return phase_init + ((pad_left + stripe_offset_inp) * phase_step) -
0256         stripe_offset_out * fir_phases;
0257 }
0258 
0259 /*
0260  * This function calculates input frame stripe width,
0261  * based on output frame stripe offset and filter parameters
0262  */
0263 static int imgu_css_osys_calc_inp_stripe_width(int stripe_width_out,
0264                            int fir_phases, int phase_init,
0265                            int phase_step, int fir_taps,
0266                            int pad_left, int pad_right)
0267 {
0268     int stripe_width_inp = (stripe_width_out + fir_taps - 1) * fir_phases;
0269 
0270     stripe_width_inp = DIV_ROUND_UP(stripe_width_inp - phase_init,
0271                     phase_step);
0272 
0273     return stripe_width_inp - pad_left - pad_right;
0274 }
0275 
0276 /*
0277  * This function calculates output frame stripe width, basedi
0278  * on output frame stripe offset and filter parameters
0279  */
0280 static int imgu_css_osys_out_stripe_width(int stripe_width_inp, int fir_phases,
0281                       int phase_init, int phase_step,
0282                       int fir_taps, int pad_left,
0283                       int pad_right, int column_offset)
0284 {
0285     int stripe_width_out = (pad_left + stripe_width_inp +
0286                 pad_right - column_offset) * phase_step;
0287 
0288     stripe_width_out = (stripe_width_out + phase_init) / fir_phases;
0289 
0290     return stripe_width_out - (fir_taps - 1);
0291 }
0292 
0293 struct imgu_css_reso {
0294     unsigned int input_width;
0295     unsigned int input_height;
0296     enum imgu_abi_frame_format input_format;
0297     unsigned int pin_width[IMGU_ABI_OSYS_PINS];
0298     unsigned int pin_height[IMGU_ABI_OSYS_PINS];
0299     unsigned int pin_stride[IMGU_ABI_OSYS_PINS];
0300     enum imgu_abi_frame_format pin_format[IMGU_ABI_OSYS_PINS];
0301     int chunk_width;
0302     int chunk_height;
0303     int block_height;
0304     int block_width;
0305 };
0306 
0307 struct imgu_css_frame_params {
0308     /* Output pins */
0309     unsigned int enable;
0310     unsigned int format;
0311     unsigned int flip;
0312     unsigned int mirror;
0313     unsigned int tiling;
0314     unsigned int reduce_range;
0315     unsigned int width;
0316     unsigned int height;
0317     unsigned int stride;
0318     unsigned int scaled;
0319     unsigned int crop_left;
0320     unsigned int crop_top;
0321 };
0322 
0323 struct imgu_css_stripe_params {
0324     unsigned int processing_mode;
0325     unsigned int phase_step;
0326     unsigned int exp_shift;
0327     unsigned int phase_init_left_y;
0328     unsigned int phase_init_left_uv;
0329     unsigned int phase_init_top_y;
0330     unsigned int phase_init_top_uv;
0331     unsigned int pad_left_y;
0332     unsigned int pad_left_uv;
0333     unsigned int pad_right_y;
0334     unsigned int pad_right_uv;
0335     unsigned int pad_top_y;
0336     unsigned int pad_top_uv;
0337     unsigned int pad_bottom_y;
0338     unsigned int pad_bottom_uv;
0339     unsigned int crop_left_y;
0340     unsigned int crop_top_y;
0341     unsigned int crop_left_uv;
0342     unsigned int crop_top_uv;
0343     unsigned int start_column_y;
0344     unsigned int start_column_uv;
0345     unsigned int chunk_width;
0346     unsigned int chunk_height;
0347     unsigned int block_width;
0348     unsigned int block_height;
0349     unsigned int input_width;
0350     unsigned int input_height;
0351     int output_width[IMGU_ABI_OSYS_PINS];
0352     int output_height[IMGU_ABI_OSYS_PINS];
0353     int output_offset[IMGU_ABI_OSYS_PINS];
0354 };
0355 
0356 /*
0357  * frame_params - size IMGU_ABI_OSYS_PINS
0358  * stripe_params - size IPU3_UAPI_MAX_STRIPES
0359  */
0360 static int imgu_css_osys_calc_frame_and_stripe_params(
0361         struct imgu_css *css, unsigned int stripes,
0362         struct imgu_abi_osys_config *osys,
0363         struct imgu_css_scaler_info *scaler_luma,
0364         struct imgu_css_scaler_info *scaler_chroma,
0365         struct imgu_css_frame_params frame_params[],
0366         struct imgu_css_stripe_params stripe_params[],
0367         unsigned int pipe)
0368 {
0369     struct imgu_css_reso reso;
0370     unsigned int output_width, pin, s;
0371     u32 input_width, input_height, target_width, target_height;
0372     unsigned int procmode = 0;
0373     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
0374 
0375     input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
0376     input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
0377     target_width = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
0378     target_height = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
0379 
0380     /* Frame parameters */
0381 
0382     /* Input width for Output System is output width of DVS (with GDC) */
0383     reso.input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
0384 
0385     /* Input height for Output System is output height of DVS (with GDC) */
0386     reso.input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
0387 
0388     reso.input_format =
0389         css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
0390 
0391     reso.pin_width[IMGU_ABI_OSYS_PIN_OUT] =
0392         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
0393     reso.pin_height[IMGU_ABI_OSYS_PIN_OUT] =
0394         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
0395     reso.pin_stride[IMGU_ABI_OSYS_PIN_OUT] =
0396         css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
0397     reso.pin_format[IMGU_ABI_OSYS_PIN_OUT] =
0398         css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
0399 
0400     reso.pin_width[IMGU_ABI_OSYS_PIN_VF] =
0401         css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
0402     reso.pin_height[IMGU_ABI_OSYS_PIN_VF] =
0403         css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
0404     reso.pin_stride[IMGU_ABI_OSYS_PIN_VF] =
0405         css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
0406     reso.pin_format[IMGU_ABI_OSYS_PIN_VF] =
0407         css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
0408 
0409     /* Configure the frame parameters for all output pins */
0410 
0411     frame_params[IMGU_ABI_OSYS_PIN_OUT].width =
0412         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
0413     frame_params[IMGU_ABI_OSYS_PIN_OUT].height =
0414         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
0415     frame_params[IMGU_ABI_OSYS_PIN_VF].width =
0416         css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
0417     frame_params[IMGU_ABI_OSYS_PIN_VF].height =
0418         css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
0419     frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 0;
0420     frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 0;
0421 
0422     for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
0423         int enable = 0;
0424         int scaled = 0;
0425         unsigned int format = 0;
0426         unsigned int tiling = 0;
0427 
0428         frame_params[pin].flip = 0;
0429         frame_params[pin].mirror = 0;
0430         frame_params[pin].reduce_range = 0;
0431         if (reso.pin_width[pin] != 0 && reso.pin_height[pin] != 0) {
0432             enable = 1;
0433             if (pin == IMGU_ABI_OSYS_PIN_OUT) {
0434                 if (reso.input_width < reso.pin_width[pin] ||
0435                     reso.input_height < reso.pin_height[pin])
0436                     return -EINVAL;
0437                 /*
0438                  * When input and output resolution is
0439                  * different instead of scaling, cropping
0440                  * should happen. Determine the crop factor
0441                  * to do the symmetric cropping
0442                  */
0443                 frame_params[pin].crop_left = roundclosest_down(
0444                         (reso.input_width -
0445                          reso.pin_width[pin]) / 2,
0446                          IMGU_OSYS_DMA_CROP_W_LIMIT);
0447                 frame_params[pin].crop_top = roundclosest_down(
0448                         (reso.input_height -
0449                          reso.pin_height[pin]) / 2,
0450                          IMGU_OSYS_DMA_CROP_H_LIMIT);
0451             } else {
0452                 if (reso.pin_width[pin] != reso.input_width ||
0453                     reso.pin_height[pin] != reso.input_height) {
0454                     /*
0455                      * If resolution is different at input
0456                      * and output of OSYS, scaling is
0457                      * considered except when pin is MAIN.
0458                      * Later it will be decide whether
0459                      * scaler factor is 1 or other
0460                      * and cropping has to be done or not.
0461                      */
0462                     scaled = 1;
0463                 }
0464             }
0465             imgu_css_osys_set_format(reso.pin_format[pin], &format,
0466                          &tiling);
0467         } else {
0468             enable = 0;
0469         }
0470         frame_params[pin].enable = enable;
0471         frame_params[pin].format = format;
0472         frame_params[pin].tiling = tiling;
0473         frame_params[pin].stride = reso.pin_stride[pin];
0474         frame_params[pin].scaled = scaled;
0475     }
0476 
0477     imgu_css_scaler_calc(input_width, input_height, target_width,
0478                  target_height, osys, scaler_luma, scaler_chroma,
0479                  &reso.pin_width[IMGU_ABI_OSYS_PIN_VF],
0480                  &reso.pin_height[IMGU_ABI_OSYS_PIN_VF], &procmode);
0481     dev_dbg(css->dev, "osys scaler procmode is %u", procmode);
0482     output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
0483 
0484     if (output_width < reso.input_width / 2) {
0485         /* Scaling factor <= 0.5 */
0486         reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH;
0487         reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
0488     } else { /* 0.5 <= Scaling factor <= 1.0 */
0489         reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH / 2;
0490         reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
0491     }
0492 
0493     if (output_width <= reso.input_width * 7 / 8) {
0494         /* Scaling factor <= 0.875 */
0495         reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT;
0496         reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
0497     } else { /* 1.0 <= Scaling factor <= 1.75 */
0498         reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT / 2;
0499         reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
0500     }
0501 
0502     /*
0503      * Calculate scaler configuration parameters based on input and output
0504      * resolution.
0505      */
0506 
0507     if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
0508         /*
0509          * When aspect ratio is different between target resolution and
0510          * required resolution, determine the crop factor to do
0511          * symmetric cropping
0512          */
0513         u32 w = reso.pin_width[IMGU_ABI_OSYS_PIN_VF] -
0514             frame_params[IMGU_ABI_OSYS_PIN_VF].width;
0515         u32 h = reso.pin_height[IMGU_ABI_OSYS_PIN_VF] -
0516             frame_params[IMGU_ABI_OSYS_PIN_VF].height;
0517 
0518         frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left =
0519             roundclosest_down(w / 2, IMGU_OSYS_DMA_CROP_W_LIMIT);
0520         frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top =
0521             roundclosest_down(h / 2, IMGU_OSYS_DMA_CROP_H_LIMIT);
0522 
0523         if (reso.input_height % 4 || reso.input_width % 8) {
0524             dev_err(css->dev, "OSYS input width is not multiple of 8 or\n");
0525             dev_err(css->dev, "height is not multiple of 4\n");
0526             return -EINVAL;
0527         }
0528     }
0529 
0530     /* Stripe parameters */
0531 
0532     if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
0533         output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
0534     } else {
0535         /*
0536          * in case scaler output is not enabled
0537          * take output width as input width since
0538          * there is no scaling at main pin.
0539          * Due to the fact that main pin can be different
0540          * from input resolution to osys in the case of cropping,
0541          * main pin resolution is not taken.
0542          */
0543         output_width = reso.input_width;
0544     }
0545 
0546     for (s = 0; s < stripes; s++) {
0547         int stripe_offset_inp_y = 0;
0548         int stripe_offset_inp_uv = 0;
0549         int stripe_offset_out_y = 0;
0550         int stripe_offset_out_uv = 0;
0551         int stripe_phase_init_y = scaler_luma->phase_init;
0552         int stripe_phase_init_uv = scaler_chroma->phase_init;
0553         int stripe_offset_blk_y = 0;
0554         int stripe_offset_blk_uv = 0;
0555         int stripe_offset_col_y = 0;
0556         int stripe_offset_col_uv = 0;
0557         int stripe_pad_left_y = scaler_luma->pad_left;
0558         int stripe_pad_left_uv = scaler_chroma->pad_left;
0559         int stripe_pad_right_y = scaler_luma->pad_right;
0560         int stripe_pad_right_uv = scaler_chroma->pad_right;
0561         int stripe_crop_left_y = scaler_luma->crop_left;
0562         int stripe_crop_left_uv = scaler_chroma->crop_left;
0563         int stripe_input_width_y = reso.input_width;
0564         int stripe_input_width_uv = 0;
0565         int stripe_output_width_y = output_width;
0566         int stripe_output_width_uv = 0;
0567         int chunk_floor_y = 0;
0568         int chunk_floor_uv = 0;
0569         int chunk_ceil_uv = 0;
0570 
0571         if (stripes > 1) {
0572             if (s > 0) {
0573                 /* Calculate stripe offsets */
0574                 stripe_offset_out_y =
0575                     output_width * s / stripes;
0576                 stripe_offset_out_y =
0577                     rounddown(stripe_offset_out_y,
0578                           IPU3_UAPI_ISP_VEC_ELEMS);
0579                 stripe_offset_out_uv = stripe_offset_out_y /
0580                         IMGU_LUMA_TO_CHROMA_RATIO;
0581                 stripe_offset_inp_y =
0582                     imgu_css_osys_calc_stripe_offset(
0583                         stripe_offset_out_y,
0584                         IMGU_OSYS_FIR_PHASES,
0585                         scaler_luma->phase_init,
0586                         scaler_luma->phase_step,
0587                         scaler_luma->pad_left);
0588                 stripe_offset_inp_uv =
0589                     imgu_css_osys_calc_stripe_offset(
0590                         stripe_offset_out_uv,
0591                         IMGU_OSYS_FIR_PHASES,
0592                         scaler_chroma->phase_init,
0593                         scaler_chroma->phase_step,
0594                         scaler_chroma->pad_left);
0595 
0596                 /* Calculate stripe phase init */
0597                 stripe_phase_init_y =
0598                     imgu_css_osys_calc_stripe_phase_init(
0599                         stripe_offset_out_y,
0600                         IMGU_OSYS_FIR_PHASES,
0601                         scaler_luma->phase_init,
0602                         scaler_luma->phase_step,
0603                         scaler_luma->pad_left);
0604                 stripe_phase_init_uv =
0605                     imgu_css_osys_calc_stripe_phase_init(
0606                         stripe_offset_out_uv,
0607                         IMGU_OSYS_FIR_PHASES,
0608                         scaler_chroma->phase_init,
0609                         scaler_chroma->phase_step,
0610                         scaler_chroma->pad_left);
0611 
0612                 /*
0613                  * Chunk boundary corner case - luma and chroma
0614                  * start from different input chunks.
0615                  */
0616                 chunk_floor_y = rounddown(stripe_offset_inp_y,
0617                               reso.chunk_width);
0618                 chunk_floor_uv =
0619                     rounddown(stripe_offset_inp_uv,
0620                           reso.chunk_width /
0621                           IMGU_LUMA_TO_CHROMA_RATIO);
0622 
0623                 if (chunk_floor_y != chunk_floor_uv *
0624                     IMGU_LUMA_TO_CHROMA_RATIO) {
0625                     /*
0626                      * Match starting luma/chroma chunks.
0627                      * Decrease offset for UV and add output
0628                      * cropping.
0629                      */
0630                     stripe_offset_inp_uv -= 1;
0631                     stripe_crop_left_uv += 1;
0632                     stripe_phase_init_uv -=
0633                         scaler_luma->phase_step;
0634                     if (stripe_phase_init_uv < 0)
0635                         stripe_phase_init_uv =
0636                             stripe_phase_init_uv +
0637                             IMGU_OSYS_FIR_PHASES;
0638                 }
0639                 /*
0640                  * FW workaround for a HW bug: if the first
0641                  * chroma pixel is generated exactly at the end
0642                  * of chunck scaler HW may not output the pixel
0643                  * for downscale factors smaller than 1.5
0644                  * (timing issue).
0645                  */
0646                 chunk_ceil_uv =
0647                     roundup(stripe_offset_inp_uv,
0648                         reso.chunk_width /
0649                         IMGU_LUMA_TO_CHROMA_RATIO);
0650 
0651                 if (stripe_offset_inp_uv ==
0652                     chunk_ceil_uv - IMGU_OSYS_TAPS_UV) {
0653                     /*
0654                      * Decrease input offset and add
0655                      * output cropping
0656                      */
0657                     stripe_offset_inp_uv -= 1;
0658                     stripe_phase_init_uv -=
0659                         scaler_luma->phase_step;
0660                     if (stripe_phase_init_uv < 0) {
0661                         stripe_phase_init_uv +=
0662                             IMGU_OSYS_FIR_PHASES;
0663                         stripe_crop_left_uv += 1;
0664                     }
0665                 }
0666 
0667                 /*
0668                  * Calculate block and column offsets for the
0669                  * input stripe
0670                  */
0671                 stripe_offset_blk_y =
0672                     rounddown(stripe_offset_inp_y,
0673                           IMGU_INPUT_BLOCK_WIDTH);
0674                 stripe_offset_blk_uv =
0675                     rounddown(stripe_offset_inp_uv,
0676                           IMGU_INPUT_BLOCK_WIDTH /
0677                           IMGU_LUMA_TO_CHROMA_RATIO);
0678                 stripe_offset_col_y = stripe_offset_inp_y -
0679                             stripe_offset_blk_y;
0680                 stripe_offset_col_uv = stripe_offset_inp_uv -
0681                             stripe_offset_blk_uv;
0682 
0683                 /* Left padding is only for the first stripe */
0684                 stripe_pad_left_y = 0;
0685                 stripe_pad_left_uv = 0;
0686             }
0687 
0688             /* Right padding is only for the last stripe */
0689             if (s < stripes - 1) {
0690                 int next_offset;
0691 
0692                 stripe_pad_right_y = 0;
0693                 stripe_pad_right_uv = 0;
0694 
0695                 next_offset = output_width * (s + 1) / stripes;
0696                 next_offset = rounddown(next_offset, 64);
0697                 stripe_output_width_y = next_offset -
0698                             stripe_offset_out_y;
0699             } else {
0700                 stripe_output_width_y = output_width -
0701                             stripe_offset_out_y;
0702             }
0703 
0704             /* Calculate target output stripe width */
0705             stripe_output_width_uv = stripe_output_width_y /
0706                         IMGU_LUMA_TO_CHROMA_RATIO;
0707             /* Calculate input stripe width */
0708             stripe_input_width_y = stripe_offset_col_y +
0709                 imgu_css_osys_calc_inp_stripe_width(
0710                         stripe_output_width_y,
0711                         IMGU_OSYS_FIR_PHASES,
0712                         stripe_phase_init_y,
0713                         scaler_luma->phase_step,
0714                         IMGU_OSYS_TAPS_Y,
0715                         stripe_pad_left_y,
0716                         stripe_pad_right_y);
0717 
0718             stripe_input_width_uv = stripe_offset_col_uv +
0719                 imgu_css_osys_calc_inp_stripe_width(
0720                         stripe_output_width_uv,
0721                         IMGU_OSYS_FIR_PHASES,
0722                         stripe_phase_init_uv,
0723                         scaler_chroma->phase_step,
0724                         IMGU_OSYS_TAPS_UV,
0725                         stripe_pad_left_uv,
0726                         stripe_pad_right_uv);
0727 
0728             stripe_input_width_uv = max(DIV_ROUND_UP(
0729                             stripe_input_width_y,
0730                             IMGU_LUMA_TO_CHROMA_RATIO),
0731                             stripe_input_width_uv);
0732 
0733             stripe_input_width_y = stripe_input_width_uv *
0734                         IMGU_LUMA_TO_CHROMA_RATIO;
0735 
0736             if (s >= stripes - 1) {
0737                 stripe_input_width_y = reso.input_width -
0738                     stripe_offset_blk_y;
0739                 /*
0740                  * The scaler requires that the last stripe
0741                  * spans at least two input blocks.
0742                  */
0743             }
0744 
0745             /*
0746              * Spec: input stripe width must be a multiple of 8.
0747              * Increase the input width and recalculate the output
0748              * width. This may produce an extra column of junk
0749              * blocks which will be overwritten by the
0750              * next stripe.
0751              */
0752             stripe_input_width_y = ALIGN(stripe_input_width_y, 8);
0753             stripe_output_width_y =
0754                 imgu_css_osys_out_stripe_width(
0755                         stripe_input_width_y,
0756                         IMGU_OSYS_FIR_PHASES,
0757                         stripe_phase_init_y,
0758                         scaler_luma->phase_step,
0759                         IMGU_OSYS_TAPS_Y,
0760                         stripe_pad_left_y,
0761                         stripe_pad_right_y,
0762                         stripe_offset_col_y);
0763 
0764             stripe_output_width_y =
0765                     rounddown(stripe_output_width_y,
0766                           IMGU_LUMA_TO_CHROMA_RATIO);
0767         }
0768         /*
0769          * Following section executes and process parameters
0770          * for both cases - Striping or No Striping.
0771          */
0772         {
0773             unsigned int i;
0774             /*Input resolution */
0775 
0776             stripe_params[s].input_width = stripe_input_width_y;
0777             stripe_params[s].input_height = reso.input_height;
0778 
0779             for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) {
0780                 if (frame_params[i].scaled) {
0781                     /*
0782                      * Output stripe resolution and offset
0783                      * as produced by the scaler; actual
0784                      * output resolution may be slightly
0785                      * smaller.
0786                      */
0787                     stripe_params[s].output_width[i] =
0788                         stripe_output_width_y;
0789                     stripe_params[s].output_height[i] =
0790                         reso.pin_height[i];
0791                     stripe_params[s].output_offset[i] =
0792                         stripe_offset_out_y;
0793                 } else {
0794                     /* Unscaled pin */
0795                     stripe_params[s].output_width[i] =
0796                         stripe_params[s].input_width;
0797                     stripe_params[s].output_height[i] =
0798                         stripe_params[s].input_height;
0799                     stripe_params[s].output_offset[i] =
0800                         stripe_offset_blk_y;
0801                 }
0802             }
0803 
0804             /* If no pin use scale, we use BYPASS mode */
0805             stripe_params[s].processing_mode = procmode;
0806             stripe_params[s].phase_step = scaler_luma->phase_step;
0807             stripe_params[s].exp_shift = scaler_luma->exp_shift;
0808             stripe_params[s].phase_init_left_y =
0809                 stripe_phase_init_y;
0810             stripe_params[s].phase_init_left_uv =
0811                 stripe_phase_init_uv;
0812             stripe_params[s].phase_init_top_y =
0813                 scaler_luma->phase_init;
0814             stripe_params[s].phase_init_top_uv =
0815                 scaler_chroma->phase_init;
0816             stripe_params[s].pad_left_y = stripe_pad_left_y;
0817             stripe_params[s].pad_left_uv = stripe_pad_left_uv;
0818             stripe_params[s].pad_right_y = stripe_pad_right_y;
0819             stripe_params[s].pad_right_uv = stripe_pad_right_uv;
0820             stripe_params[s].pad_top_y = scaler_luma->pad_left;
0821             stripe_params[s].pad_top_uv = scaler_chroma->pad_left;
0822             stripe_params[s].pad_bottom_y = scaler_luma->pad_right;
0823             stripe_params[s].pad_bottom_uv =
0824                 scaler_chroma->pad_right;
0825             stripe_params[s].crop_left_y = stripe_crop_left_y;
0826             stripe_params[s].crop_top_y = scaler_luma->crop_top;
0827             stripe_params[s].crop_left_uv = stripe_crop_left_uv;
0828             stripe_params[s].crop_top_uv = scaler_chroma->crop_top;
0829             stripe_params[s].start_column_y = stripe_offset_col_y;
0830             stripe_params[s].start_column_uv = stripe_offset_col_uv;
0831             stripe_params[s].chunk_width = reso.chunk_width;
0832             stripe_params[s].chunk_height = reso.chunk_height;
0833             stripe_params[s].block_width = reso.block_width;
0834             stripe_params[s].block_height = reso.block_height;
0835         }
0836     }
0837 
0838     return 0;
0839 }
0840 
0841 /*
0842  * This function configures the Output Formatter System, given the number of
0843  * stripes, scaler luma and chrome parameters
0844  */
0845 static int imgu_css_osys_calc(struct imgu_css *css, unsigned int pipe,
0846                   unsigned int stripes,
0847                   struct imgu_abi_osys_config *osys,
0848                   struct imgu_css_scaler_info *scaler_luma,
0849                   struct imgu_css_scaler_info *scaler_chroma,
0850                   struct imgu_abi_stripes block_stripes[])
0851 {
0852     struct imgu_css_frame_params frame_params[IMGU_ABI_OSYS_PINS];
0853     struct imgu_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES];
0854     struct imgu_abi_osys_formatter_params *param;
0855     unsigned int pin, s;
0856     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
0857 
0858     memset(osys, 0, sizeof(*osys));
0859 
0860     /* Compute the frame and stripe params */
0861     if (imgu_css_osys_calc_frame_and_stripe_params(css, stripes, osys,
0862                                scaler_luma,
0863                                scaler_chroma,
0864                                frame_params,
0865                                stripe_params, pipe))
0866         return -EINVAL;
0867 
0868     /* Output formatter system parameters */
0869 
0870     for (s = 0; s < stripes; s++) {
0871         struct imgu_abi_osys_scaler_params *scaler =
0872                     &osys->scaler[s].param;
0873         int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT;
0874         int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP;
0875 
0876         /* OUTPUT 0 / PIN 0 is only Scaler output */
0877         scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
0878 
0879         /*
0880          * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
0881          * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) /
0882          *   (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
0883          * = 2 * 64 / 32 = 4
0884          */
0885         scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE;
0886         /*
0887          * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size)
0888          * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) +
0889          *  (VMEM1_y_size / 4)
0890          * = (VMEM1_y_size) + (VMEM1_y_size / 4) +
0891          * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4
0892          * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
0893          */
0894         scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
0895         scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
0896                         IMGU_VMEM1_U_OFFSET;
0897         scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
0898                         IMGU_VMEM1_V_OFFSET;
0899         scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE;
0900         scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
0901         scaler->inp_buf_chunk_width = stripe_params[s].chunk_width;
0902         scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS;
0903 
0904         /* Output buffers */
0905         scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
0906         scaler->out_buf_y_line_stride = stripe_params[s].block_width /
0907                         IMGU_VMEM1_ELEMS_PER_VEC;
0908         scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
0909         scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
0910                         IMGU_VMEM1_U_OFFSET;
0911         scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
0912                         IMGU_VMEM1_V_OFFSET;
0913         scaler->out_buf_uv_line_stride = stripe_params[s].block_width /
0914                         IMGU_VMEM1_ELEMS_PER_VEC / 2;
0915         scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
0916         scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS;
0917 
0918         /* Intermediate buffers */
0919         scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR;
0920         scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE;
0921         scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR;
0922         scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR;
0923         scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE;
0924         scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK;
0925         scaler->int_buf_chunk_width = stripe_params[s].chunk_height;
0926         scaler->int_buf_chunk_height = stripe_params[s].block_width;
0927 
0928         /* Context buffers */
0929         scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR;
0930         scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR;
0931         scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR;
0932         scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR;
0933         scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR;
0934         scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR;
0935 
0936         /* Addresses for release-input and process-output tokens */
0937         scaler->release_inp_buf_addr = fifo_addr_ack;
0938         scaler->release_inp_buf_en = 1;
0939         scaler->release_out_buf_en = 1;
0940         scaler->process_out_buf_addr = fifo_addr_fmt;
0941 
0942         /* Settings dimensions, padding, cropping */
0943         scaler->input_image_y_width = stripe_params[s].input_width;
0944         scaler->input_image_y_height = stripe_params[s].input_height;
0945         scaler->input_image_y_start_column =
0946                     stripe_params[s].start_column_y;
0947         scaler->input_image_uv_start_column =
0948                     stripe_params[s].start_column_uv;
0949         scaler->input_image_y_left_pad = stripe_params[s].pad_left_y;
0950         scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv;
0951         scaler->input_image_y_right_pad = stripe_params[s].pad_right_y;
0952         scaler->input_image_uv_right_pad =
0953                     stripe_params[s].pad_right_uv;
0954         scaler->input_image_y_top_pad = stripe_params[s].pad_top_y;
0955         scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv;
0956         scaler->input_image_y_bottom_pad =
0957                     stripe_params[s].pad_bottom_y;
0958         scaler->input_image_uv_bottom_pad =
0959                     stripe_params[s].pad_bottom_uv;
0960         scaler->processing_mode = stripe_params[s].processing_mode;
0961         scaler->scaling_ratio = stripe_params[s].phase_step;
0962         scaler->y_left_phase_init = stripe_params[s].phase_init_left_y;
0963         scaler->uv_left_phase_init =
0964                     stripe_params[s].phase_init_left_uv;
0965         scaler->y_top_phase_init = stripe_params[s].phase_init_top_y;
0966         scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv;
0967         scaler->coeffs_exp_shift = stripe_params[s].exp_shift;
0968         scaler->out_y_left_crop = stripe_params[s].crop_left_y;
0969         scaler->out_uv_left_crop = stripe_params[s].crop_left_uv;
0970         scaler->out_y_top_crop = stripe_params[s].crop_top_y;
0971         scaler->out_uv_top_crop = stripe_params[s].crop_top_uv;
0972 
0973         for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
0974             int in_fifo_addr;
0975             int out_fifo_addr;
0976             int block_width_vecs;
0977             int input_width_s;
0978             int input_width_vecs;
0979             int input_buf_y_st_addr;
0980             int input_buf_u_st_addr;
0981             int input_buf_v_st_addr;
0982             int input_buf_y_line_stride;
0983             int input_buf_uv_line_stride;
0984             int output_buf_y_line_stride;
0985             int output_buf_uv_line_stride;
0986             int output_buf_nr_y_lines;
0987             int block_height;
0988             int block_width;
0989             struct imgu_abi_osys_frame_params *fr_pr;
0990 
0991             fr_pr = &osys->frame[pin].param;
0992 
0993             /* Frame parameters */
0994             fr_pr->enable = frame_params[pin].enable;
0995             fr_pr->format = frame_params[pin].format;
0996             fr_pr->mirror = frame_params[pin].mirror;
0997             fr_pr->flip = frame_params[pin].flip;
0998             fr_pr->tiling = frame_params[pin].tiling;
0999             fr_pr->width = frame_params[pin].width;
1000             fr_pr->height = frame_params[pin].height;
1001             fr_pr->stride = frame_params[pin].stride;
1002             fr_pr->scaled = frame_params[pin].scaled;
1003 
1004             /* Stripe parameters */
1005             osys->stripe[s].crop_top[pin] =
1006                 frame_params[pin].crop_top;
1007             osys->stripe[s].input_width =
1008                 stripe_params[s].input_width;
1009             osys->stripe[s].input_height =
1010                 stripe_params[s].input_height;
1011             osys->stripe[s].block_height =
1012                 stripe_params[s].block_height;
1013             osys->stripe[s].block_width =
1014                 stripe_params[s].block_width;
1015             osys->stripe[s].output_width[pin] =
1016                 stripe_params[s].output_width[pin];
1017             osys->stripe[s].output_height[pin] =
1018                 stripe_params[s].output_height[pin];
1019 
1020             if (s == 0) {
1021                 /* Only first stripe should do left cropping */
1022                 osys->stripe[s].crop_left[pin] =
1023                     frame_params[pin].crop_left;
1024                 osys->stripe[s].output_offset[pin] =
1025                     stripe_params[s].output_offset[pin];
1026             } else {
1027                 /*
1028                  * Stripe offset for other strips should be
1029                  * adjusted according to the cropping done
1030                  * at the first strip
1031                  */
1032                 osys->stripe[s].crop_left[pin] = 0;
1033                 osys->stripe[s].output_offset[pin] =
1034                     (stripe_params[s].output_offset[pin] -
1035                      osys->stripe[0].crop_left[pin]);
1036             }
1037 
1038             if (!frame_params[pin].enable)
1039                 continue;
1040 
1041             /* Formatter: configurations */
1042 
1043             /*
1044              * Get the dimensions of the input blocks of the
1045              * formatter, which is the same as the output
1046              * blocks of the scaler.
1047              */
1048             if (frame_params[pin].scaled) {
1049                 block_height = stripe_params[s].block_height;
1050                 block_width = stripe_params[s].block_width;
1051             } else {
1052                 block_height = IMGU_OSYS_BLOCK_HEIGHT;
1053                 block_width = IMGU_OSYS_BLOCK_WIDTH;
1054             }
1055             block_width_vecs =
1056                     block_width / IMGU_VMEM1_ELEMS_PER_VEC;
1057             /*
1058              * The input/output line stride depends on the
1059              * block size.
1060              */
1061             input_buf_y_line_stride = block_width_vecs;
1062             input_buf_uv_line_stride = block_width_vecs / 2;
1063             output_buf_y_line_stride = block_width_vecs;
1064             output_buf_uv_line_stride = block_width_vecs / 2;
1065             output_buf_nr_y_lines = block_height;
1066             if (frame_params[pin].format ==
1067                 IMGU_ABI_OSYS_FORMAT_NV12 ||
1068                 frame_params[pin].format ==
1069                 IMGU_ABI_OSYS_FORMAT_NV21)
1070                 output_buf_uv_line_stride =
1071                     output_buf_y_line_stride;
1072 
1073             /*
1074              * Tiled outputs use a different output buffer
1075              * configuration. The input (= scaler output) block
1076              * width translates to a tile height, and the block
1077              * height to the tile width. The default block size of
1078              * 128x32 maps exactly onto a 4kB tile (512x8) for Y.
1079              * For UV, the tile width is always half.
1080              */
1081             if (frame_params[pin].tiling) {
1082                 output_buf_nr_y_lines = 8;
1083                 output_buf_y_line_stride = 512 /
1084                     IMGU_VMEM1_ELEMS_PER_VEC;
1085                 output_buf_uv_line_stride = 256 /
1086                     IMGU_VMEM1_ELEMS_PER_VEC;
1087             }
1088 
1089             /*
1090              * Store the output buffer line stride. Will be
1091              * used to compute buffer offsets in boundary
1092              * conditions when output blocks are partially
1093              * outside the image.
1094              */
1095             osys->stripe[s].buf_stride[pin] =
1096                 output_buf_y_line_stride *
1097                 IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS;
1098             if (frame_params[pin].scaled) {
1099                 /*
1100                  * The input buffs are the intermediate
1101                  * buffers (scalers' output)
1102                  */
1103                 input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
1104                 input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
1105                             IMGU_VMEM1_U_OFFSET;
1106                 input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
1107                             IMGU_VMEM1_V_OFFSET;
1108             } else {
1109                 /*
1110                  * The input bufferss are the buffers
1111                  * filled by the SP
1112                  */
1113                 input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
1114                 input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
1115                             IMGU_VMEM1_U_OFFSET;
1116                 input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
1117                             IMGU_VMEM1_V_OFFSET;
1118             }
1119 
1120             /*
1121              * The formatter input width must be rounded to
1122              * the block width. Otherwise the formatter will
1123              * not recognize the end of the line, resulting
1124              * in incorrect tiling (system may hang!) and
1125              * possibly other problems.
1126              */
1127             input_width_s =
1128                 roundup(stripe_params[s].output_width[pin],
1129                     block_width);
1130             input_width_vecs = input_width_s /
1131                     IMGU_VMEM1_ELEMS_PER_VEC;
1132             out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
1133             /*
1134              * Process-output tokens must be sent to the SP.
1135              * When scaling, the release-input tokens can be
1136              * sent directly to the scaler, otherwise the
1137              * formatter should send them to the SP.
1138              */
1139             if (frame_params[pin].scaled)
1140                 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER;
1141             else
1142                 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
1143 
1144             /* Formatter */
1145             param = &osys->formatter[s][pin].param;
1146 
1147             param->format = frame_params[pin].format;
1148             param->flip = frame_params[pin].flip;
1149             param->mirror = frame_params[pin].mirror;
1150             param->tiling = frame_params[pin].tiling;
1151             param->reduce_range = frame_params[pin].reduce_range;
1152             param->alpha_blending = 0;
1153             param->release_inp_addr = in_fifo_addr;
1154             param->release_inp_en = 1;
1155             param->process_out_buf_addr = out_fifo_addr;
1156             param->image_width_vecs = input_width_vecs;
1157             param->image_height_lines =
1158                 stripe_params[s].output_height[pin];
1159             param->inp_buff_y_st_addr = input_buf_y_st_addr;
1160             param->inp_buff_y_line_stride = input_buf_y_line_stride;
1161             param->inp_buff_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
1162             param->int_buff_u_st_addr = input_buf_u_st_addr;
1163             param->int_buff_v_st_addr = input_buf_v_st_addr;
1164             param->inp_buff_uv_line_stride =
1165                 input_buf_uv_line_stride;
1166             param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
1167             param->out_buff_level = 0;
1168             param->out_buff_nr_y_lines = output_buf_nr_y_lines;
1169             param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET;
1170             param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET;
1171             param->out_buff_y_line_stride =
1172                 output_buf_y_line_stride;
1173             param->out_buff_uv_line_stride =
1174                 output_buf_uv_line_stride;
1175             param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR;
1176             param->hist_buff_line_stride =
1177                 IMGU_VMEM1_HST_BUF_STRIDE;
1178             param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES;
1179         }
1180     }
1181 
1182     block_stripes[0].offset = 0;
1183     if (stripes <= 1) {
1184         block_stripes[0].width = stripe_params[0].input_width;
1185         block_stripes[0].height = stripe_params[0].input_height;
1186     } else {
1187         struct imgu_fw_info *bi =
1188             &css->fwp->binary_header[css_pipe->bindex];
1189         unsigned int sp_block_width =
1190                 bi->info.isp.sp.block.block_width *
1191                 IPU3_UAPI_ISP_VEC_ELEMS;
1192 
1193         block_stripes[0].width = roundup(stripe_params[0].input_width,
1194                          sp_block_width);
1195         block_stripes[1].offset =
1196             rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
1197                   stripe_params[1].input_width, sp_block_width);
1198         block_stripes[1].width =
1199             roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
1200                 block_stripes[1].offset, sp_block_width);
1201         block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
1202         block_stripes[1].height = block_stripes[0].height;
1203     }
1204 
1205     return 0;
1206 }
1207 
1208 /*********************** Mostly 3A operations ******************************/
1209 
1210 /*
1211  * This function creates a "TO-DO list" (operations) for the sp code.
1212  *
1213  * There are 2 types of operations:
1214  * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to
1215  *    accelerator space (NOTE that this space is limited) associated data:
1216  *    DDR address + accelerator's config set index(acc's address).
1217  *
1218  * 2. Issue "Process Lines Command" to shd accelerator
1219  *    associated data: #lines + which config set to use (actually, accelerator
1220  *    will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction
1221  *    of not touching config sets x & (x+1)%num_of_sets when process_lines(x)
1222  *    is active).
1223  *
1224  * Basically there are 2 types of operations "chunks":
1225  * 1. "initial chunk": Initially, we do as much transfers as we can (and need)
1226  *    [0 - max sets(3) ] followed by 1 or 2 "process lines" operations.
1227  *
1228  * 2. "regular chunk" - 1 transfer followed by 1 process line operation.
1229  *    (in some cases we might need additional transfer ate the last chunk).
1230  *
1231  * for some case:
1232  * --> init
1233  *  tr (0)
1234  *  tr (1)
1235  *  tr (2)
1236  *  pl (0)
1237  *  pl (1)
1238  * --> ack (0)
1239  *  tr (3)
1240  *  pl (2)
1241  * --> ack (1)
1242  *  pl (3)
1243  * --> ack (2)
1244  *  do nothing
1245  * --> ack (3)
1246  *  do nothing
1247  */
1248 
1249 static int
1250 imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops,
1251               const struct ipu3_uapi_shd_grid_config *grid,
1252               unsigned int image_height)
1253 {
1254     unsigned int block_height = 1 << grid->block_height_log2;
1255     unsigned int grid_height_per_slice = grid->grid_height_per_slice;
1256     unsigned int set_height = grid_height_per_slice * block_height;
1257 
1258     /* We currently support only abs(y_start) > grid_height_per_slice */
1259     unsigned int positive_y_start = (unsigned int)-grid->y_start;
1260     unsigned int first_process_lines =
1261                 set_height - (positive_y_start % set_height);
1262     unsigned int last_set_height;
1263     unsigned int num_of_sets;
1264 
1265     struct imgu_abi_acc_operation *p_op;
1266     struct imgu_abi_acc_process_lines_cmd_data *p_pl;
1267     struct imgu_abi_shd_transfer_luts_set_data *p_tr;
1268 
1269     unsigned int op_idx, pl_idx, tr_idx;
1270     unsigned char tr_set_num, pl_cfg_set;
1271 
1272     /*
1273      * When the number of lines for the last process lines command
1274      * is equal to a set height, we need another line of grid cell -
1275      * additional transfer is required.
1276      */
1277     unsigned char last_tr = 0;
1278 
1279     /* Add "process lines" command to the list of operations */
1280     bool add_pl;
1281     /* Add DMA xfer (config set) command to the list of ops */
1282     bool add_tr;
1283 
1284     /*
1285      * Available partial grid (the part that fits into #IMGU_SHD_SETS sets)
1286      * doesn't cover whole frame - need to process in chunks
1287      */
1288     if (image_height > first_process_lines) {
1289         last_set_height =
1290             (image_height - first_process_lines) % set_height;
1291         num_of_sets = last_set_height > 0 ?
1292             (image_height - first_process_lines) / set_height + 2 :
1293             (image_height - first_process_lines) / set_height + 1;
1294         last_tr = (set_height - last_set_height <= block_height ||
1295                last_set_height == 0) ? 1 : 0;
1296     } else { /* partial grid covers whole frame */
1297         last_set_height = 0;
1298         num_of_sets = 1;
1299         first_process_lines = image_height;
1300         last_tr = set_height - image_height <= block_height ? 1 : 0;
1301     }
1302 
1303     /* Init operations lists and counters */
1304     p_op = ops->operation_list;
1305     op_idx = 0;
1306     p_pl = ops->process_lines_data;
1307     pl_idx = 0;
1308     p_tr = ops->transfer_data;
1309     tr_idx = 0;
1310 
1311     memset(ops, 0, sizeof(*ops));
1312 
1313     /* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */
1314     tr_set_num = 0;
1315     pl_cfg_set = 0;
1316 
1317     /*
1318      * Always start with a transfer - process lines command must be
1319      * initiated only after appropriate config sets are in place
1320      * (2 configuration sets per process line command, except for last one).
1321      */
1322     add_pl = false;
1323     add_tr = true;
1324 
1325     while (add_pl || add_tr) {
1326         /* Transfer ops */
1327         if (add_tr) {
1328             if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
1329                 tr_idx >= IMGU_ABI_SHD_MAX_TRANSFERS)
1330                 return -EINVAL;
1331             p_op[op_idx].op_type =
1332                 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
1333             p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE;
1334             op_idx++;
1335             p_tr[tr_idx].set_number = tr_set_num;
1336             tr_idx++;
1337             tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS;
1338         }
1339 
1340         /* Process-lines ops */
1341         if (add_pl) {
1342             if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
1343                 pl_idx >= IMGU_ABI_SHD_MAX_PROCESS_LINES)
1344                 return -EINVAL;
1345             p_op[op_idx].op_type =
1346                 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1347 
1348             /*
1349              * In case we have 2 process lines commands -
1350              * don't stop after the first one
1351              */
1352             if (pl_idx == 0 && num_of_sets != 1)
1353                 p_op[op_idx].op_indicator =
1354                     IMGU_ABI_ACC_OP_IDLE;
1355             /*
1356              * Initiate last process lines command -
1357              * end of operation list.
1358              */
1359             else if (pl_idx == num_of_sets - 1)
1360                 p_op[op_idx].op_indicator =
1361                     IMGU_ABI_ACC_OP_END_OF_OPS;
1362             /*
1363              * Intermediate process line command - end of operation
1364              * "chunk" (meaning few "transfers" followed by few
1365              * "process lines" commands).
1366              */
1367             else
1368                 p_op[op_idx].op_indicator =
1369                     IMGU_ABI_ACC_OP_END_OF_ACK;
1370 
1371             op_idx++;
1372 
1373             /* first process line operation */
1374             if (pl_idx == 0)
1375                 p_pl[pl_idx].lines = first_process_lines;
1376             /* Last process line operation */
1377             else if (pl_idx == num_of_sets - 1 &&
1378                  last_set_height > 0)
1379                 p_pl[pl_idx].lines = last_set_height;
1380             else    /* "regular" process lines operation */
1381                 p_pl[pl_idx].lines = set_height;
1382 
1383             p_pl[pl_idx].cfg_set = pl_cfg_set;
1384             pl_idx++;
1385             pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS;
1386         }
1387 
1388         /*
1389          * Initially, we always transfer
1390          * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the
1391          * corresponding process lines commands.
1392          */
1393         if (tr_idx == IMGU_SHD_SETS ||
1394             tr_idx == num_of_sets + last_tr) {
1395             add_tr = false;
1396             add_pl = true;
1397         }
1398 
1399         /*
1400          * We have finished the "initial" operations chunk -
1401          * be ready to get more chunks.
1402          */
1403         if (pl_idx == 2) {
1404             add_tr = true;
1405             add_pl = true;
1406         }
1407 
1408         /* Stop conditions for each operation type */
1409         if (tr_idx == num_of_sets + last_tr)
1410             add_tr = false;
1411         if (pl_idx == num_of_sets)
1412             add_pl = false;
1413     }
1414 
1415     return 0;
1416 }
1417 
1418 /*
1419  * The follow handshake procotol is the same for AF, AWB and AWB FR.
1420  *
1421  * for n sets of meta-data, the flow is:
1422  * --> init
1423  *  process-lines  (0)
1424  *  process-lines  (1)   eoc
1425  *  --> ack (0)
1426  *  read-meta-data (0)
1427  *  process-lines  (2)   eoc
1428  *  --> ack (1)
1429  *  read-meta-data (1)
1430  *  process-lines  (3)   eoc
1431  *  ...
1432  *
1433  *  --> ack (n-3)
1434  *  read-meta-data (n-3)
1435  *  process-lines  (n-1) eoc
1436  *  --> ack (n-2)
1437  *  read-meta-data (n-2) eoc
1438  *  --> ack (n-1)
1439  *  read-meta-data (n-1) eof
1440  *
1441  * for 2 sets we get:
1442  * --> init
1443  * pl (0)
1444  * pl (1) eoc
1445  * --> ack (0)
1446  * pl (2) - rest of image, if applicable)
1447  * rmd (0) eoc
1448  * --> ack (1)
1449  * rmd (1) eof
1450  * --> (ack (2))
1451  * do nothing
1452  *
1453  * for only one set:
1454  *
1455  * --> init
1456  * pl(0)   eoc
1457  * --> ack (0)
1458  * rmd (0) eof
1459  *
1460  * grid smaller than image case
1461  * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
1462  * start at (0,0)
1463  * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
1464  * => 1st process lines = 80
1465  * we're left with 128-80=48 lines (6 blocks vertical)
1466  * => 2nd process lines = 48
1467  * last process lines to cover the image - image_height - 128
1468  *
1469  * --> init
1470  * pl (0) first
1471  * pl (1) last-in-grid
1472  * --> ack (0)
1473  * rmd (0)
1474  * pl (2) after-grid
1475  * --> ack (1)
1476  * rmd (1) eof
1477  * --> ack (2)
1478  * do nothing
1479  */
1480 struct process_lines {
1481     unsigned int image_height;
1482     unsigned short grid_height;
1483     unsigned short block_height;
1484     unsigned short y_start;
1485     unsigned char grid_height_per_slice;
1486 
1487     unsigned short max_op; /* max operation */
1488     unsigned short max_tr; /* max transaction */
1489     unsigned char acc_enable;
1490 };
1491 
1492 /* Helper to config intra_frame_operations_data. */
1493 static int
1494 imgu_css_acc_process_lines(const struct process_lines *pl,
1495                struct imgu_abi_acc_operation *p_op,
1496                struct imgu_abi_acc_process_lines_cmd_data *p_pl,
1497                struct imgu_abi_acc_transfer_op_data *p_tr)
1498 {
1499     unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0;
1500     unsigned char tr_set_num = 0, pl_cfg_set = 0;
1501     const unsigned short grid_last_line =
1502             pl->y_start + pl->grid_height * pl->block_height;
1503     const unsigned short process_lines =
1504             pl->grid_height_per_slice * pl->block_height;
1505 
1506     unsigned int process_lines_after_grid;
1507     unsigned short first_process_lines;
1508     unsigned short last_process_lines_in_grid;
1509 
1510     unsigned short num_of_process_lines;
1511     unsigned short num_of_sets;
1512 
1513     if (pl->grid_height_per_slice == 0)
1514         return -EINVAL;
1515 
1516     if (pl->acc_enable && grid_last_line > pl->image_height)
1517         return -EINVAL;
1518 
1519     num_of_sets = pl->grid_height / pl->grid_height_per_slice;
1520     if (num_of_sets * pl->grid_height_per_slice < pl->grid_height)
1521         num_of_sets++;
1522 
1523     /* Account for two line delay inside the FF */
1524     if (pl->max_op == IMGU_ABI_AF_MAX_OPERATIONS) {
1525         first_process_lines = process_lines + pl->y_start + 2;
1526         last_process_lines_in_grid =
1527             (grid_last_line - first_process_lines) -
1528             ((num_of_sets - 2) * process_lines) + 4;
1529         process_lines_after_grid =
1530             pl->image_height - grid_last_line - 4;
1531     } else {
1532         first_process_lines = process_lines + pl->y_start;
1533         last_process_lines_in_grid =
1534             (grid_last_line - first_process_lines) -
1535             ((num_of_sets - 2) * process_lines);
1536         process_lines_after_grid = pl->image_height - grid_last_line;
1537     }
1538 
1539     num_of_process_lines = num_of_sets;
1540     if (process_lines_after_grid > 0)
1541         num_of_process_lines++;
1542 
1543     while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) {
1544         /* Read meta-data */
1545         if (pl_idx >= 2 || (pl_idx == 1 && num_of_sets == 1)) {
1546             if (op_idx >= pl->max_op || tr_idx >= pl->max_tr)
1547                 return -EINVAL;
1548 
1549             p_op[op_idx].op_type =
1550                 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
1551 
1552             if (tr_idx == num_of_sets - 1)
1553                 /* The last operation is always a tr */
1554                 p_op[op_idx].op_indicator =
1555                     IMGU_ABI_ACC_OP_END_OF_OPS;
1556             else if (tr_idx == num_of_sets - 2)
1557                 if (process_lines_after_grid == 0)
1558                     /*
1559                      * No additional pl op left -
1560                      * this op is left as lats of cycle
1561                      */
1562                     p_op[op_idx].op_indicator =
1563                         IMGU_ABI_ACC_OP_END_OF_ACK;
1564                 else
1565                     /*
1566                      * We still have to process-lines after
1567                      * the grid so have one more pl op
1568                      */
1569                     p_op[op_idx].op_indicator =
1570                         IMGU_ABI_ACC_OP_IDLE;
1571             else
1572                 /* Default - usually there's a pl after a tr */
1573                 p_op[op_idx].op_indicator =
1574                     IMGU_ABI_ACC_OP_IDLE;
1575 
1576             op_idx++;
1577             if (p_tr) {
1578                 p_tr[tr_idx].set_number = tr_set_num;
1579                 tr_set_num = 1 - tr_set_num;
1580             }
1581             tr_idx++;
1582         }
1583 
1584         /* process_lines */
1585         if (pl_idx < num_of_process_lines) {
1586             if (op_idx >= pl->max_op || pl_idx >= pl->max_tr)
1587                 return -EINVAL;
1588 
1589             p_op[op_idx].op_type =
1590                 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1591             if (pl_idx == 0)
1592                 if (num_of_process_lines == 1)
1593                     /* Only one pl op */
1594                     p_op[op_idx].op_indicator =
1595                         IMGU_ABI_ACC_OP_END_OF_ACK;
1596                 else
1597                     /* On init - do two pl ops */
1598                     p_op[op_idx].op_indicator =
1599                         IMGU_ABI_ACC_OP_IDLE;
1600             else
1601                 /* Usually pl is the end of the ack cycle */
1602                 p_op[op_idx].op_indicator =
1603                     IMGU_ABI_ACC_OP_END_OF_ACK;
1604 
1605             op_idx++;
1606 
1607             if (pl_idx == 0)
1608                 /* First process line */
1609                 p_pl[pl_idx].lines = first_process_lines;
1610             else if (pl_idx == num_of_sets - 1)
1611                 /* Last in grid */
1612                 p_pl[pl_idx].lines = last_process_lines_in_grid;
1613             else if (pl_idx == num_of_process_lines - 1)
1614                 /* After the grid */
1615                 p_pl[pl_idx].lines = process_lines_after_grid;
1616             else
1617                 /* Inside the grid */
1618                 p_pl[pl_idx].lines = process_lines;
1619 
1620             if (p_tr) {
1621                 p_pl[pl_idx].cfg_set = pl_cfg_set;
1622                 pl_cfg_set = 1 - pl_cfg_set;
1623             }
1624             pl_idx++;
1625         }
1626     }
1627 
1628     return 0;
1629 }
1630 
1631 static int imgu_css_af_ops_calc(struct imgu_css *css, unsigned int pipe,
1632                 struct imgu_abi_af_config *af_config)
1633 {
1634     struct imgu_abi_af_intra_frame_operations_data *to =
1635         &af_config->operations_data;
1636     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1637     struct imgu_fw_info *bi =
1638         &css->fwp->binary_header[css_pipe->bindex];
1639 
1640     struct process_lines pl = {
1641         .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1642         .grid_height = af_config->config.grid_cfg.height,
1643         .block_height =
1644             1 << af_config->config.grid_cfg.block_height_log2,
1645         .y_start = af_config->config.grid_cfg.y_start &
1646             IPU3_UAPI_GRID_START_MASK,
1647         .grid_height_per_slice =
1648             af_config->stripes[0].grid_cfg.height_per_slice,
1649         .max_op = IMGU_ABI_AF_MAX_OPERATIONS,
1650         .max_tr = IMGU_ABI_AF_MAX_TRANSFERS,
1651         .acc_enable = bi->info.isp.sp.enable.af,
1652     };
1653 
1654     return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1655                       NULL);
1656 }
1657 
1658 static int
1659 imgu_css_awb_fr_ops_calc(struct imgu_css *css, unsigned int pipe,
1660              struct imgu_abi_awb_fr_config *awb_fr_config)
1661 {
1662     struct imgu_abi_awb_fr_intra_frame_operations_data *to =
1663         &awb_fr_config->operations_data;
1664     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1665     struct imgu_fw_info *bi =
1666         &css->fwp->binary_header[css_pipe->bindex];
1667     struct process_lines pl = {
1668         .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1669         .grid_height = awb_fr_config->config.grid_cfg.height,
1670         .block_height =
1671             1 << awb_fr_config->config.grid_cfg.block_height_log2,
1672         .y_start = awb_fr_config->config.grid_cfg.y_start &
1673             IPU3_UAPI_GRID_START_MASK,
1674         .grid_height_per_slice =
1675             awb_fr_config->stripes[0].grid_cfg.height_per_slice,
1676         .max_op = IMGU_ABI_AWB_FR_MAX_OPERATIONS,
1677         .max_tr = IMGU_ABI_AWB_FR_MAX_PROCESS_LINES,
1678         .acc_enable = bi->info.isp.sp.enable.awb_fr_acc,
1679     };
1680 
1681     return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1682                       NULL);
1683 }
1684 
1685 static int imgu_css_awb_ops_calc(struct imgu_css *css, unsigned int pipe,
1686                  struct imgu_abi_awb_config *awb_config)
1687 {
1688     struct imgu_abi_awb_intra_frame_operations_data *to =
1689         &awb_config->operations_data;
1690     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1691     struct imgu_fw_info *bi =
1692         &css->fwp->binary_header[css_pipe->bindex];
1693 
1694     struct process_lines pl = {
1695         .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1696         .grid_height = awb_config->config.grid.height,
1697         .block_height =
1698             1 << awb_config->config.grid.block_height_log2,
1699         .y_start = awb_config->config.grid.y_start,
1700         .grid_height_per_slice =
1701             awb_config->stripes[0].grid.height_per_slice,
1702         .max_op = IMGU_ABI_AWB_MAX_OPERATIONS,
1703         .max_tr = IMGU_ABI_AWB_MAX_TRANSFERS,
1704         .acc_enable = bi->info.isp.sp.enable.awb_acc,
1705     };
1706 
1707     return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1708                       to->transfer_data);
1709 }
1710 
1711 static u16 imgu_css_grid_end(u16 start, u8 width, u8 block_width_log2)
1712 {
1713     return (start & IPU3_UAPI_GRID_START_MASK) +
1714         (width << block_width_log2) - 1;
1715 }
1716 
1717 static void imgu_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg)
1718 {
1719     grid_cfg->x_end = imgu_css_grid_end(grid_cfg->x_start, grid_cfg->width,
1720                         grid_cfg->block_width_log2);
1721     grid_cfg->y_end = imgu_css_grid_end(grid_cfg->y_start, grid_cfg->height,
1722                         grid_cfg->block_height_log2);
1723 }
1724 
1725 /****************** config computation *****************************/
1726 
1727 static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe,
1728                    struct imgu_abi_acc_param *acc)
1729 {
1730     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1731     const struct imgu_fw_info *bi =
1732         &css->fwp->binary_header[css_pipe->bindex];
1733     struct imgu_css_scaler_info scaler_luma, scaler_chroma;
1734     const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
1735     const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2;
1736     unsigned int bds_ds, i;
1737 
1738     memset(acc, 0, sizeof(*acc));
1739 
1740     /* acc_param: osys_config */
1741 
1742     if (imgu_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma,
1743                    &scaler_chroma, acc->stripe.block_stripes))
1744         return -EINVAL;
1745 
1746     /* acc_param: stripe data */
1747 
1748     /*
1749      * For the striped case the approach is as follows:
1750      * 1. down-scaled stripes are calculated - with 128 overlap
1751      *    (this is the main limiter therefore it's first)
1752      * 2. input stripes are derived by up-scaling the down-scaled stripes
1753      *    (there are no alignment requirements on input stripes)
1754      * 3. output stripes are derived from down-scaled stripes too
1755      */
1756 
1757     acc->stripe.num_of_stripes = stripes;
1758     acc->stripe.input_frame.width =
1759         css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
1760     acc->stripe.input_frame.height =
1761         css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
1762     acc->stripe.input_frame.bayer_order =
1763         css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
1764 
1765     for (i = 0; i < stripes; i++)
1766         acc->stripe.bds_out_stripes[i].height =
1767                     css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1768     acc->stripe.bds_out_stripes[0].offset = 0;
1769     if (stripes <= 1) {
1770         acc->stripe.bds_out_stripes[0].width =
1771             ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
1772     } else {
1773         /* Image processing is divided into two stripes */
1774         acc->stripe.bds_out_stripes[0].width =
1775             acc->stripe.bds_out_stripes[1].width =
1776             (css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f;
1777         /*
1778          * Sum of width of the two stripes should not be smaller
1779          * than output width and must be even times of overlapping
1780          * unit f.
1781          */
1782         if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) !=
1783             !!(css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1)))
1784             acc->stripe.bds_out_stripes[0].width += f;
1785         if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) &&
1786             (css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) {
1787             acc->stripe.bds_out_stripes[0].width += f;
1788             acc->stripe.bds_out_stripes[1].width += f;
1789         }
1790         /* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
1791         acc->stripe.bds_out_stripes[1].offset =
1792             acc->stripe.bds_out_stripes[0].width - 2 * f;
1793     }
1794 
1795     acc->stripe.effective_stripes[0].height =
1796                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
1797     acc->stripe.effective_stripes[0].offset = 0;
1798     acc->stripe.bds_out_stripes_no_overlap[0].height =
1799                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1800     acc->stripe.bds_out_stripes_no_overlap[0].offset = 0;
1801     acc->stripe.output_stripes[0].height =
1802                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1803     acc->stripe.output_stripes[0].offset = 0;
1804     if (stripes <= 1) {
1805         acc->stripe.down_scaled_stripes[0].width =
1806                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1807         acc->stripe.down_scaled_stripes[0].height =
1808                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1809         acc->stripe.down_scaled_stripes[0].offset = 0;
1810 
1811         acc->stripe.effective_stripes[0].width =
1812                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
1813         acc->stripe.bds_out_stripes_no_overlap[0].width =
1814             ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
1815 
1816         acc->stripe.output_stripes[0].width =
1817             css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
1818     } else { /* Two stripes */
1819         bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width *
1820                 IMGU_BDS_GRANULARITY /
1821                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1822 
1823         acc->stripe.down_scaled_stripes[0] =
1824             acc->stripe.bds_out_stripes[0];
1825         acc->stripe.down_scaled_stripes[1] =
1826             acc->stripe.bds_out_stripes[1];
1827         if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f))
1828             acc->stripe.down_scaled_stripes[1].width +=
1829                 (css_pipe->rect[IPU3_CSS_RECT_BDS].width
1830                 & (f - 1)) - f;
1831 
1832         acc->stripe.effective_stripes[0].width = bds_ds *
1833             acc->stripe.down_scaled_stripes[0].width /
1834             IMGU_BDS_GRANULARITY;
1835         acc->stripe.effective_stripes[1].width = bds_ds *
1836             acc->stripe.down_scaled_stripes[1].width /
1837             IMGU_BDS_GRANULARITY;
1838         acc->stripe.effective_stripes[1].height =
1839             css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
1840         acc->stripe.effective_stripes[1].offset = bds_ds *
1841             acc->stripe.down_scaled_stripes[1].offset /
1842             IMGU_BDS_GRANULARITY;
1843 
1844         acc->stripe.bds_out_stripes_no_overlap[0].width =
1845         acc->stripe.bds_out_stripes_no_overlap[1].offset =
1846             ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2;
1847         acc->stripe.bds_out_stripes_no_overlap[1].width =
1848             DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)
1849             / 2 * f;
1850         acc->stripe.bds_out_stripes_no_overlap[1].height =
1851             css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1852 
1853         acc->stripe.output_stripes[0].width =
1854             acc->stripe.down_scaled_stripes[0].width - f;
1855         acc->stripe.output_stripes[1].width =
1856             acc->stripe.down_scaled_stripes[1].width - f;
1857         acc->stripe.output_stripes[1].height =
1858             css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1859         acc->stripe.output_stripes[1].offset =
1860             acc->stripe.output_stripes[0].width;
1861     }
1862 
1863     acc->stripe.output_system_in_frame_width =
1864         css_pipe->rect[IPU3_CSS_RECT_GDC].width;
1865     acc->stripe.output_system_in_frame_height =
1866         css_pipe->rect[IPU3_CSS_RECT_GDC].height;
1867 
1868     acc->stripe.effective_frame_width =
1869                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
1870     acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1871     acc->stripe.out_frame_width =
1872         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
1873     acc->stripe.out_frame_height =
1874         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1875     acc->stripe.gdc_in_buffer_width =
1876         css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
1877         css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
1878     acc->stripe.gdc_in_buffer_height =
1879         css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
1880     acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X;
1881     acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y;
1882     acc->stripe.display_frame_width =
1883         css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
1884     acc->stripe.display_frame_height =
1885         css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
1886     acc->stripe.bds_aligned_frame_width =
1887         roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
1888             2 * IPU3_UAPI_ISP_VEC_ELEMS);
1889 
1890     if (stripes > 1)
1891         acc->stripe.half_overlap_vectors =
1892             IMGU_STRIPE_FIXED_HALF_OVERLAP;
1893     else
1894         acc->stripe.half_overlap_vectors = 0;
1895 
1896     return 0;
1897 }
1898 
1899 static void imgu_css_cfg_acc_dvs(struct imgu_css *css,
1900                  struct imgu_abi_acc_param *acc,
1901                  unsigned int pipe)
1902 {
1903     unsigned int i;
1904     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1905 
1906     /* Disable DVS statistics */
1907     acc->dvs_stat.operations_data.process_lines_data[0].lines =
1908                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1909     acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0;
1910     acc->dvs_stat.operations_data.ops[0].op_type =
1911         IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1912     acc->dvs_stat.operations_data.ops[0].op_indicator =
1913         IMGU_ABI_ACC_OP_NO_OPS;
1914     for (i = 0; i < IMGU_ABI_DVS_STAT_LEVELS; i++)
1915         acc->dvs_stat.cfg.grd_config[i].enable = 0;
1916 }
1917 
1918 static void acc_bds_per_stripe_data(struct imgu_css *css,
1919                     struct imgu_abi_acc_param *acc,
1920                     const int i, unsigned int pipe)
1921 {
1922     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1923 
1924     acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0;
1925     acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0;
1926     acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0;
1927     acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 =
1928         acc->bds.hor.hor_ctrl0;
1929     acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width =
1930         acc->stripe.down_scaled_stripes[i].width;
1931     acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width =
1932         acc->stripe.down_scaled_stripes[i].width;
1933     acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height =
1934         css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1935 }
1936 
1937 /*
1938  * Configure `acc' parameters. `acc_old' contains the old values (or is NULL)
1939  * and `acc_user' contains new prospective values. `use' contains flags
1940  * telling which fields to take from the old values (or generate if it is NULL)
1941  * and which to take from the new user values.
1942  */
1943 int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe,
1944              struct ipu3_uapi_flags *use,
1945              struct imgu_abi_acc_param *acc,
1946              struct imgu_abi_acc_param *acc_old,
1947              struct ipu3_uapi_acc_param *acc_user)
1948 {
1949     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1950     const struct imgu_fw_info *bi =
1951         &css->fwp->binary_header[css_pipe->bindex];
1952     const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
1953     const unsigned int tnr_frame_width =
1954         acc->stripe.bds_aligned_frame_width;
1955     const unsigned int min_overlap = 10;
1956     const struct v4l2_pix_format_mplane *pixm =
1957         &css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
1958     const struct imgu_css_bds_config *cfg_bds;
1959     struct imgu_abi_input_feeder_data *feeder_data;
1960 
1961     unsigned int bds_ds, ofs_x, ofs_y, i, width, height;
1962     u8 b_w_log2; /* Block width log2 */
1963 
1964     /* Update stripe using chroma and luma */
1965 
1966     if (imgu_css_cfg_acc_stripe(css, pipe, acc))
1967         return -EINVAL;
1968 
1969     /* acc_param: input_feeder_config */
1970 
1971     ofs_x = ((pixm->width -
1972           css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
1973     ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1974         IMGU_ABI_BAYER_ORDER_RGGB ||
1975         css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1976         IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
1977     ofs_y = ((pixm->height -
1978           css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
1979     ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1980         IMGU_ABI_BAYER_ORDER_BGGR ||
1981         css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1982         IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
1983     acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline;
1984     acc->input_feeder.data.start_row_address =
1985         ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
1986         ofs_y * acc->input_feeder.data.row_stride;
1987     acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
1988 
1989     acc->input_feeder.data_per_stripe.input_feeder_data[0].data =
1990         acc->input_feeder.data;
1991 
1992     ofs_x += acc->stripe.effective_stripes[1].offset;
1993 
1994     feeder_data =
1995         &acc->input_feeder.data_per_stripe.input_feeder_data[1].data;
1996     feeder_data->row_stride = acc->input_feeder.data.row_stride;
1997     feeder_data->start_row_address =
1998         ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
1999         ofs_y * acc->input_feeder.data.row_stride;
2000     feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
2001 
2002     /* acc_param: bnr_static_config */
2003 
2004     /*
2005      * Originate from user or be the original default values if user has
2006      * never set them before, when user gives a new set of parameters,
2007      * for each chunk in the parameter structure there is a flag use->xxx
2008      * whether to use the user-provided parameter or not. If not, the
2009      * parameter remains unchanged in the driver:
2010      * it's value is taken from acc_old.
2011      */
2012     if (use && use->acc_bnr) {
2013         /* Take values from user */
2014         acc->bnr = acc_user->bnr;
2015     } else if (acc_old) {
2016         /* Use old value */
2017         acc->bnr = acc_old->bnr;
2018     } else {
2019         /* Calculate from scratch */
2020         acc->bnr = imgu_css_bnr_defaults;
2021     }
2022 
2023     acc->bnr.column_size = tnr_frame_width;
2024 
2025     /* acc_param: bnr_static_config_green_disparity */
2026 
2027     if (use && use->acc_green_disparity) {
2028         /* Take values from user */
2029         acc->green_disparity = acc_user->green_disparity;
2030     } else if (acc_old) {
2031         /* Use old value */
2032         acc->green_disparity = acc_old->green_disparity;
2033     } else {
2034         /* Calculate from scratch */
2035         memset(&acc->green_disparity, 0, sizeof(acc->green_disparity));
2036     }
2037 
2038     /* acc_param: dm_config */
2039 
2040     if (use && use->acc_dm) {
2041         /* Take values from user */
2042         acc->dm = acc_user->dm;
2043     } else if (acc_old) {
2044         /* Use old value */
2045         acc->dm = acc_old->dm;
2046     } else {
2047         /* Calculate from scratch */
2048         acc->dm = imgu_css_dm_defaults;
2049     }
2050 
2051     acc->dm.frame_width = tnr_frame_width;
2052 
2053     /* acc_param: ccm_mat_config */
2054 
2055     if (use && use->acc_ccm) {
2056         /* Take values from user */
2057         acc->ccm = acc_user->ccm;
2058     } else if (acc_old) {
2059         /* Use old value */
2060         acc->ccm = acc_old->ccm;
2061     } else {
2062         /* Calculate from scratch */
2063         acc->ccm = imgu_css_ccm_defaults;
2064     }
2065 
2066     /* acc_param: gamma_config */
2067 
2068     if (use && use->acc_gamma) {
2069         /* Take values from user */
2070         acc->gamma = acc_user->gamma;
2071     } else if (acc_old) {
2072         /* Use old value */
2073         acc->gamma = acc_old->gamma;
2074     } else {
2075         /* Calculate from scratch */
2076         acc->gamma.gc_ctrl.enable = 1;
2077         acc->gamma.gc_lut = imgu_css_gamma_lut;
2078     }
2079 
2080     /* acc_param: csc_mat_config */
2081 
2082     if (use && use->acc_csc) {
2083         /* Take values from user */
2084         acc->csc = acc_user->csc;
2085     } else if (acc_old) {
2086         /* Use old value */
2087         acc->csc = acc_old->csc;
2088     } else {
2089         /* Calculate from scratch */
2090         acc->csc = imgu_css_csc_defaults;
2091     }
2092 
2093     /* acc_param: cds_params */
2094 
2095     if (use && use->acc_cds) {
2096         /* Take values from user */
2097         acc->cds = acc_user->cds;
2098     } else if (acc_old) {
2099         /* Use old value */
2100         acc->cds = acc_old->cds;
2101     } else {
2102         /* Calculate from scratch */
2103         acc->cds = imgu_css_cds_defaults;
2104     }
2105 
2106     /* acc_param: shd_config */
2107 
2108     if (use && use->acc_shd) {
2109         /* Take values from user */
2110         acc->shd.shd = acc_user->shd.shd;
2111         acc->shd.shd_lut = acc_user->shd.shd_lut;
2112     } else if (acc_old) {
2113         /* Use old value */
2114         acc->shd.shd = acc_old->shd.shd;
2115         acc->shd.shd_lut = acc_old->shd.shd_lut;
2116     } else {
2117         /* Calculate from scratch */
2118         acc->shd.shd = imgu_css_shd_defaults;
2119         memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut));
2120     }
2121 
2122     if (acc->shd.shd.grid.width <= 0)
2123         return -EINVAL;
2124 
2125     acc->shd.shd.grid.grid_height_per_slice =
2126         IMGU_ABI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width;
2127 
2128     if (acc->shd.shd.grid.grid_height_per_slice <= 0)
2129         return -EINVAL;
2130 
2131     acc->shd.shd.general.init_set_vrt_offst_ul =
2132                 (-acc->shd.shd.grid.y_start >>
2133                  acc->shd.shd.grid.block_height_log2) %
2134                 acc->shd.shd.grid.grid_height_per_slice;
2135 
2136     if (imgu_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid,
2137                   css_pipe->rect[IPU3_CSS_RECT_BDS].height))
2138         return -EINVAL;
2139 
2140     /* acc_param: dvs_stat_config */
2141     imgu_css_cfg_acc_dvs(css, acc, pipe);
2142 
2143     /* acc_param: yuvp1_iefd_config */
2144 
2145     if (use && use->acc_iefd) {
2146         /* Take values from user */
2147         acc->iefd = acc_user->iefd;
2148     } else if (acc_old) {
2149         /* Use old value */
2150         acc->iefd = acc_old->iefd;
2151     } else {
2152         /* Calculate from scratch */
2153         acc->iefd = imgu_css_iefd_defaults;
2154     }
2155 
2156     /* acc_param: yuvp1_yds_config yds_c0 */
2157 
2158     if (use && use->acc_yds_c0) {
2159         /* Take values from user */
2160         acc->yds_c0 = acc_user->yds_c0;
2161     } else if (acc_old) {
2162         /* Use old value */
2163         acc->yds_c0 = acc_old->yds_c0;
2164     } else {
2165         /* Calculate from scratch */
2166         acc->yds_c0 = imgu_css_yds_defaults;
2167     }
2168 
2169     /* acc_param: yuvp1_chnr_config chnr_c0 */
2170 
2171     if (use && use->acc_chnr_c0) {
2172         /* Take values from user */
2173         acc->chnr_c0 = acc_user->chnr_c0;
2174     } else if (acc_old) {
2175         /* Use old value */
2176         acc->chnr_c0 = acc_old->chnr_c0;
2177     } else {
2178         /* Calculate from scratch */
2179         acc->chnr_c0 = imgu_css_chnr_defaults;
2180     }
2181 
2182     /* acc_param: yuvp1_y_ee_nr_config */
2183 
2184     if (use && use->acc_y_ee_nr) {
2185         /* Take values from user */
2186         acc->y_ee_nr = acc_user->y_ee_nr;
2187     } else if (acc_old) {
2188         /* Use old value */
2189         acc->y_ee_nr = acc_old->y_ee_nr;
2190     } else {
2191         /* Calculate from scratch */
2192         acc->y_ee_nr = imgu_css_y_ee_nr_defaults;
2193     }
2194 
2195     /* acc_param: yuvp1_yds_config yds */
2196 
2197     if (use && use->acc_yds) {
2198         /* Take values from user */
2199         acc->yds = acc_user->yds;
2200     } else if (acc_old) {
2201         /* Use old value */
2202         acc->yds = acc_old->yds;
2203     } else {
2204         /* Calculate from scratch */
2205         acc->yds = imgu_css_yds_defaults;
2206     }
2207 
2208     /* acc_param: yuvp1_chnr_config chnr */
2209 
2210     if (use && use->acc_chnr) {
2211         /* Take values from user */
2212         acc->chnr = acc_user->chnr;
2213     } else if (acc_old) {
2214         /* Use old value */
2215         acc->chnr = acc_old->chnr;
2216     } else {
2217         /* Calculate from scratch */
2218         acc->chnr = imgu_css_chnr_defaults;
2219     }
2220 
2221     /* acc_param: yuvp2_y_tm_lut_static_config */
2222 
2223     for (i = 0; i < IMGU_ABI_YUVP2_YTM_LUT_ENTRIES; i++)
2224         acc->ytm.entries[i] = i * 32;
2225     acc->ytm.enable = 0;    /* Always disabled on IPU3 */
2226 
2227     /* acc_param: yuvp1_yds_config yds2 */
2228 
2229     if (use && use->acc_yds2) {
2230         /* Take values from user */
2231         acc->yds2 = acc_user->yds2;
2232     } else if (acc_old) {
2233         /* Use old value */
2234         acc->yds2 = acc_old->yds2;
2235     } else {
2236         /* Calculate from scratch */
2237         acc->yds2 = imgu_css_yds_defaults;
2238     }
2239 
2240     /* acc_param: yuvp2_tcc_static_config */
2241 
2242     if (use && use->acc_tcc) {
2243         /* Take values from user */
2244         acc->tcc = acc_user->tcc;
2245     } else if (acc_old) {
2246         /* Use old value */
2247         acc->tcc = acc_old->tcc;
2248     } else {
2249         /* Calculate from scratch */
2250         memset(&acc->tcc, 0, sizeof(acc->tcc));
2251 
2252         acc->tcc.gen_control.en = 1;
2253         acc->tcc.gen_control.blend_shift = 3;
2254         acc->tcc.gen_control.gain_according_to_y_only = 1;
2255         acc->tcc.gen_control.gamma = 8;
2256         acc->tcc.gen_control.delta = 0;
2257 
2258         for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) {
2259             acc->tcc.macc_table.entries[i].a = 1024;
2260             acc->tcc.macc_table.entries[i].b = 0;
2261             acc->tcc.macc_table.entries[i].c = 0;
2262             acc->tcc.macc_table.entries[i].d = 1024;
2263         }
2264 
2265         acc->tcc.inv_y_lut.entries[6] = 1023;
2266         for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++)
2267             acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6);
2268 
2269         acc->tcc.gain_pcwl = imgu_css_tcc_gain_pcwl_lut;
2270         acc->tcc.r_sqr_lut = imgu_css_tcc_r_sqr_lut;
2271     }
2272 
2273     /* acc_param: dpc_config */
2274 
2275     if (use && use->acc_dpc)
2276         return -EINVAL; /* Not supported yet */
2277 
2278     /* Just disable by default */
2279     memset(&acc->dpc, 0, sizeof(acc->dpc));
2280 
2281     /* acc_param: bds_config */
2282 
2283     bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height *
2284           IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2285     if (bds_ds < IMGU_BDS_MIN_SF_INV ||
2286         bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(imgu_css_bds_configs))
2287         return -EINVAL;
2288 
2289     cfg_bds = &imgu_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV];
2290     acc->bds.hor.hor_ctrl1.hor_crop_en = 0;
2291     acc->bds.hor.hor_ctrl1.hor_crop_start = 0;
2292     acc->bds.hor.hor_ctrl1.hor_crop_end = 0;
2293     acc->bds.hor.hor_ctrl0.sample_patrn_length =
2294                 cfg_bds->sample_patrn_length;
2295     acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en;
2296     acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
2297     acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
2298     acc->bds.hor.hor_ctrl0.out_frame_width =
2299                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
2300     acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr;
2301     acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr;
2302     acc->bds.hor.hor_ctrl2.input_frame_height =
2303                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
2304     acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
2305     acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
2306     acc->bds.ver.ver_ctrl0.sample_patrn_length =
2307                 cfg_bds->sample_patrn_length;
2308     acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en;
2309     acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr;
2310     acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr;
2311     acc->bds.ver.ver_ctrl1.out_frame_width =
2312                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
2313     acc->bds.ver.ver_ctrl1.out_frame_height =
2314                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2315     for (i = 0; i < stripes; i++)
2316         acc_bds_per_stripe_data(css, acc, i, pipe);
2317 
2318     acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en;
2319 
2320     /* acc_param: anr_config */
2321 
2322     if (use && use->acc_anr) {
2323         /* Take values from user */
2324         acc->anr.transform = acc_user->anr.transform;
2325         acc->anr.stitch.anr_stitch_en =
2326             acc_user->anr.stitch.anr_stitch_en;
2327         memcpy(acc->anr.stitch.pyramid, acc_user->anr.stitch.pyramid,
2328                sizeof(acc->anr.stitch.pyramid));
2329     } else if (acc_old) {
2330         /* Use old value */
2331         acc->anr.transform = acc_old->anr.transform;
2332         acc->anr.stitch.anr_stitch_en =
2333             acc_old->anr.stitch.anr_stitch_en;
2334         memcpy(acc->anr.stitch.pyramid, acc_old->anr.stitch.pyramid,
2335                sizeof(acc->anr.stitch.pyramid));
2336     } else {
2337         /* Calculate from scratch */
2338         acc->anr = imgu_css_anr_defaults;
2339     }
2340 
2341     /* Always enabled */
2342     acc->anr.search.enable = 1;
2343     acc->anr.transform.enable = 1;
2344     acc->anr.tile2strm.enable = 1;
2345     acc->anr.tile2strm.frame_width =
2346         ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2347     acc->anr.search.frame_width = acc->anr.tile2strm.frame_width;
2348     acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width;
2349     acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2350     acc->anr.search.frame_height = acc->anr.tile2strm.frame_height;
2351     acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height;
2352 
2353     width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2354     height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2355 
2356     if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET)
2357         acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width;
2358     if (acc->anr.transform.xreset < IPU3_UAPI_ANR_MIN_RESET)
2359         acc->anr.transform.xreset = IPU3_UAPI_ANR_MIN_RESET;
2360 
2361     if (acc->anr.transform.yreset + height > IPU3_UAPI_ANR_MAX_RESET)
2362         acc->anr.transform.yreset = IPU3_UAPI_ANR_MAX_RESET - height;
2363     if (acc->anr.transform.yreset < IPU3_UAPI_ANR_MIN_RESET)
2364         acc->anr.transform.yreset = IPU3_UAPI_ANR_MIN_RESET;
2365 
2366     /* acc_param: awb_fr_config */
2367 
2368     if (use && use->acc_awb_fr) {
2369         /* Take values from user */
2370         acc->awb_fr.config = acc_user->awb_fr;
2371     } else if (acc_old) {
2372         /* Use old value */
2373         acc->awb_fr.config = acc_old->awb_fr.config;
2374     } else {
2375         /* Set from scratch */
2376         acc->awb_fr.config = imgu_css_awb_fr_defaults;
2377     }
2378 
2379     imgu_css_grid_end_calc(&acc->awb_fr.config.grid_cfg);
2380 
2381     if (acc->awb_fr.config.grid_cfg.width <= 0)
2382         return -EINVAL;
2383 
2384     acc->awb_fr.config.grid_cfg.height_per_slice =
2385         IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET /
2386         acc->awb_fr.config.grid_cfg.width;
2387 
2388     for (i = 0; i < stripes; i++)
2389         acc->awb_fr.stripes[i] = acc->awb_fr.config;
2390 
2391     if (acc->awb_fr.config.grid_cfg.x_start >=
2392         acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2393         /* Enable only for rightmost stripe, disable left */
2394         acc->awb_fr.stripes[0].grid_cfg.y_start &=
2395                     ~IPU3_UAPI_GRID_Y_START_EN;
2396     } else if (acc->awb_fr.config.grid_cfg.x_end <=
2397            acc->stripe.bds_out_stripes[0].width - min_overlap) {
2398         /* Enable only for leftmost stripe, disable right */
2399         acc->awb_fr.stripes[1].grid_cfg.y_start &=
2400                     ~IPU3_UAPI_GRID_Y_START_EN;
2401     } else {
2402         /* Enable for both stripes */
2403         u16 end; /* width for grid end */
2404 
2405         acc->awb_fr.stripes[0].grid_cfg.width =
2406             (acc->stripe.bds_out_stripes[0].width - min_overlap -
2407              acc->awb_fr.config.grid_cfg.x_start + 1) >>
2408             acc->awb_fr.config.grid_cfg.block_width_log2;
2409         acc->awb_fr.stripes[1].grid_cfg.width =
2410             acc->awb_fr.config.grid_cfg.width -
2411             acc->awb_fr.stripes[0].grid_cfg.width;
2412 
2413         b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2;
2414         end = imgu_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start,
2415                     acc->awb_fr.stripes[0].grid_cfg.width,
2416                     b_w_log2);
2417         acc->awb_fr.stripes[0].grid_cfg.x_end = end;
2418 
2419         acc->awb_fr.stripes[1].grid_cfg.x_start =
2420             (acc->awb_fr.stripes[0].grid_cfg.x_end + 1 -
2421              acc->stripe.down_scaled_stripes[1].offset) &
2422             IPU3_UAPI_GRID_START_MASK;
2423         b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2;
2424         end = imgu_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start,
2425                     acc->awb_fr.stripes[1].grid_cfg.width,
2426                     b_w_log2);
2427         acc->awb_fr.stripes[1].grid_cfg.x_end = end;
2428 
2429         /*
2430          * To reduce complexity of debubbling and loading
2431          * statistics fix grid_height_per_slice to 1 for both
2432          * stripes.
2433          */
2434         for (i = 0; i < stripes; i++)
2435             acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1;
2436     }
2437 
2438     if (imgu_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr))
2439         return -EINVAL;
2440 
2441     /* acc_param: ae_config */
2442 
2443     if (use && use->acc_ae) {
2444         /* Take values from user */
2445         acc->ae.grid_cfg = acc_user->ae.grid_cfg;
2446         acc->ae.ae_ccm = acc_user->ae.ae_ccm;
2447         for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2448             acc->ae.weights[i] = acc_user->ae.weights[i];
2449     } else if (acc_old) {
2450         /* Use old value */
2451         acc->ae.grid_cfg = acc_old->ae.grid_cfg;
2452         acc->ae.ae_ccm = acc_old->ae.ae_ccm;
2453         for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2454             acc->ae.weights[i] = acc_old->ae.weights[i];
2455     } else {
2456         /* Set from scratch */
2457         static const struct ipu3_uapi_ae_weight_elem
2458             weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 };
2459 
2460         acc->ae.grid_cfg = imgu_css_ae_grid_defaults;
2461         acc->ae.ae_ccm = imgu_css_ae_ccm_defaults;
2462         for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2463             acc->ae.weights[i] = weight_def;
2464     }
2465 
2466     b_w_log2 = acc->ae.grid_cfg.block_width_log2;
2467     acc->ae.grid_cfg.x_end = imgu_css_grid_end(acc->ae.grid_cfg.x_start,
2468                            acc->ae.grid_cfg.width,
2469                            b_w_log2);
2470     b_w_log2 = acc->ae.grid_cfg.block_height_log2;
2471     acc->ae.grid_cfg.y_end = imgu_css_grid_end(acc->ae.grid_cfg.y_start,
2472                            acc->ae.grid_cfg.height,
2473                            b_w_log2);
2474 
2475     for (i = 0; i < stripes; i++)
2476         acc->ae.stripes[i].grid = acc->ae.grid_cfg;
2477 
2478     if (acc->ae.grid_cfg.x_start >=
2479         acc->stripe.down_scaled_stripes[1].offset) {
2480         /* Enable only for rightmost stripe, disable left */
2481         acc->ae.stripes[0].grid.ae_en = 0;
2482     } else if (acc->ae.grid_cfg.x_end <=
2483            acc->stripe.bds_out_stripes[0].width) {
2484         /* Enable only for leftmost stripe, disable right */
2485         acc->ae.stripes[1].grid.ae_en = 0;
2486     } else {
2487         /* Enable for both stripes */
2488         u8 b_w_log2;
2489 
2490         acc->ae.stripes[0].grid.width =
2491             (acc->stripe.bds_out_stripes[0].width -
2492              acc->ae.grid_cfg.x_start + 1) >>
2493             acc->ae.grid_cfg.block_width_log2;
2494 
2495         acc->ae.stripes[1].grid.width =
2496             acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width;
2497 
2498         b_w_log2 = acc->ae.stripes[0].grid.block_width_log2;
2499         acc->ae.stripes[0].grid.x_end =
2500             imgu_css_grid_end(acc->ae.stripes[0].grid.x_start,
2501                       acc->ae.stripes[0].grid.width,
2502                       b_w_log2);
2503 
2504         acc->ae.stripes[1].grid.x_start =
2505             (acc->ae.stripes[0].grid.x_end + 1 -
2506              acc->stripe.down_scaled_stripes[1].offset) &
2507             IPU3_UAPI_GRID_START_MASK;
2508         b_w_log2 = acc->ae.stripes[1].grid.block_width_log2;
2509         acc->ae.stripes[1].grid.x_end =
2510             imgu_css_grid_end(acc->ae.stripes[1].grid.x_start,
2511                       acc->ae.stripes[1].grid.width,
2512                       b_w_log2);
2513     }
2514 
2515     /* acc_param: af_config */
2516 
2517     if (use && use->acc_af) {
2518         /* Take values from user */
2519         acc->af.config.filter_config = acc_user->af.filter_config;
2520         acc->af.config.grid_cfg = acc_user->af.grid_cfg;
2521     } else if (acc_old) {
2522         /* Use old value */
2523         acc->af.config = acc_old->af.config;
2524     } else {
2525         /* Set from scratch */
2526         acc->af.config.filter_config =
2527                 imgu_css_af_defaults.filter_config;
2528         acc->af.config.grid_cfg = imgu_css_af_defaults.grid_cfg;
2529     }
2530 
2531     imgu_css_grid_end_calc(&acc->af.config.grid_cfg);
2532 
2533     if (acc->af.config.grid_cfg.width <= 0)
2534         return -EINVAL;
2535 
2536     acc->af.config.grid_cfg.height_per_slice =
2537         IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width;
2538     acc->af.config.frame_size.width =
2539         ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2540     acc->af.config.frame_size.height =
2541         css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2542 
2543     if (acc->stripe.bds_out_stripes[0].width <= min_overlap)
2544         return -EINVAL;
2545 
2546     for (i = 0; i < stripes; i++) {
2547         acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg;
2548         acc->af.stripes[i].frame_size.height =
2549                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2550         acc->af.stripes[i].frame_size.width =
2551             acc->stripe.bds_out_stripes[i].width;
2552     }
2553 
2554     if (acc->af.config.grid_cfg.x_start >=
2555         acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2556         /* Enable only for rightmost stripe, disable left */
2557         acc->af.stripes[0].grid_cfg.y_start &=
2558             ~IPU3_UAPI_GRID_Y_START_EN;
2559         acc->af.stripes[1].grid_cfg.x_start =
2560             (acc->af.stripes[1].grid_cfg.x_start -
2561              acc->stripe.down_scaled_stripes[1].offset) &
2562             IPU3_UAPI_GRID_START_MASK;
2563         b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2;
2564         acc->af.stripes[1].grid_cfg.x_end =
2565             imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start,
2566                       acc->af.stripes[1].grid_cfg.width,
2567                       b_w_log2);
2568     } else if (acc->af.config.grid_cfg.x_end <=
2569            acc->stripe.bds_out_stripes[0].width - min_overlap) {
2570         /* Enable only for leftmost stripe, disable right */
2571         acc->af.stripes[1].grid_cfg.y_start &=
2572             ~IPU3_UAPI_GRID_Y_START_EN;
2573     } else {
2574         /* Enable for both stripes */
2575 
2576         acc->af.stripes[0].grid_cfg.width =
2577             (acc->stripe.bds_out_stripes[0].width - min_overlap -
2578              acc->af.config.grid_cfg.x_start + 1) >>
2579             acc->af.config.grid_cfg.block_width_log2;
2580         acc->af.stripes[1].grid_cfg.width =
2581             acc->af.config.grid_cfg.width -
2582             acc->af.stripes[0].grid_cfg.width;
2583 
2584         b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2;
2585         acc->af.stripes[0].grid_cfg.x_end =
2586             imgu_css_grid_end(acc->af.stripes[0].grid_cfg.x_start,
2587                       acc->af.stripes[0].grid_cfg.width,
2588                       b_w_log2);
2589 
2590         acc->af.stripes[1].grid_cfg.x_start =
2591             (acc->af.stripes[0].grid_cfg.x_end + 1 -
2592              acc->stripe.down_scaled_stripes[1].offset) &
2593             IPU3_UAPI_GRID_START_MASK;
2594 
2595         b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2;
2596         acc->af.stripes[1].grid_cfg.x_end =
2597             imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start,
2598                       acc->af.stripes[1].grid_cfg.width,
2599                       b_w_log2);
2600 
2601         /*
2602          * To reduce complexity of debubbling and loading statistics
2603          * fix grid_height_per_slice to 1 for both stripes
2604          */
2605         for (i = 0; i < stripes; i++)
2606             acc->af.stripes[i].grid_cfg.height_per_slice = 1;
2607     }
2608 
2609     if (imgu_css_af_ops_calc(css, pipe, &acc->af))
2610         return -EINVAL;
2611 
2612     /* acc_param: awb_config */
2613 
2614     if (use && use->acc_awb) {
2615         /* Take values from user */
2616         acc->awb.config = acc_user->awb.config;
2617     } else if (acc_old) {
2618         /* Use old value */
2619         acc->awb.config = acc_old->awb.config;
2620     } else {
2621         /* Set from scratch */
2622         acc->awb.config = imgu_css_awb_defaults;
2623     }
2624 
2625     if (acc->awb.config.grid.width <= 0)
2626         return -EINVAL;
2627 
2628     acc->awb.config.grid.height_per_slice =
2629         IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width,
2630     imgu_css_grid_end_calc(&acc->awb.config.grid);
2631 
2632     for (i = 0; i < stripes; i++)
2633         acc->awb.stripes[i] = acc->awb.config;
2634 
2635     if (acc->awb.config.grid.x_start >=
2636         acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2637         /* Enable only for rightmost stripe, disable left */
2638         acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
2639 
2640         acc->awb.stripes[1].grid.x_start =
2641             (acc->awb.stripes[1].grid.x_start -
2642              acc->stripe.down_scaled_stripes[1].offset) &
2643             IPU3_UAPI_GRID_START_MASK;
2644 
2645         b_w_log2 = acc->awb.stripes[1].grid.block_width_log2;
2646         acc->awb.stripes[1].grid.x_end =
2647             imgu_css_grid_end(acc->awb.stripes[1].grid.x_start,
2648                       acc->awb.stripes[1].grid.width,
2649                       b_w_log2);
2650     } else if (acc->awb.config.grid.x_end <=
2651            acc->stripe.bds_out_stripes[0].width - min_overlap) {
2652         /* Enable only for leftmost stripe, disable right */
2653         acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
2654     } else {
2655         /* Enable for both stripes */
2656 
2657         acc->awb.stripes[0].grid.width =
2658             (acc->stripe.bds_out_stripes[0].width -
2659              acc->awb.config.grid.x_start + 1) >>
2660             acc->awb.config.grid.block_width_log2;
2661         acc->awb.stripes[1].grid.width = acc->awb.config.grid.width -
2662                 acc->awb.stripes[0].grid.width;
2663 
2664         b_w_log2 = acc->awb.stripes[0].grid.block_width_log2;
2665         acc->awb.stripes[0].grid.x_end =
2666             imgu_css_grid_end(acc->awb.stripes[0].grid.x_start,
2667                       acc->awb.stripes[0].grid.width,
2668                       b_w_log2);
2669 
2670         acc->awb.stripes[1].grid.x_start =
2671             (acc->awb.stripes[0].grid.x_end + 1 -
2672              acc->stripe.down_scaled_stripes[1].offset) &
2673             IPU3_UAPI_GRID_START_MASK;
2674 
2675         b_w_log2 = acc->awb.stripes[1].grid.block_width_log2;
2676         acc->awb.stripes[1].grid.x_end =
2677             imgu_css_grid_end(acc->awb.stripes[1].grid.x_start,
2678                       acc->awb.stripes[1].grid.width,
2679                       b_w_log2);
2680 
2681         /*
2682          * To reduce complexity of debubbling and loading statistics
2683          * fix grid_height_per_slice to 1 for both stripes
2684          */
2685         for (i = 0; i < stripes; i++)
2686             acc->awb.stripes[i].grid.height_per_slice = 1;
2687     }
2688 
2689     if (imgu_css_awb_ops_calc(css, pipe, &acc->awb))
2690         return -EINVAL;
2691 
2692     return 0;
2693 }
2694 
2695 /*
2696  * Fill the indicated structure in `new_binary_params' from the possible
2697  * sources based on `use_user' flag: if the flag is false, copy from
2698  * `old_binary_params', or if the flag is true, copy from `user_setting'
2699  * and return NULL (or error pointer on error).
2700  * If the flag is false and `old_binary_params' is NULL, return pointer
2701  * to the structure inside `new_binary_params'. In that case the caller
2702  * should calculate and fill the structure from scratch.
2703  */
2704 static void *imgu_css_cfg_copy(struct imgu_css *css,
2705                    unsigned int pipe, bool use_user,
2706                    void *user_setting, void *old_binary_params,
2707                    void *new_binary_params,
2708                    enum imgu_abi_memories m,
2709                    struct imgu_fw_isp_parameter *par,
2710                    size_t par_size)
2711 {
2712     const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2713     void *new_setting, *old_setting;
2714 
2715     new_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par,
2716                           par_size, new_binary_params);
2717     if (!new_setting)
2718         return ERR_PTR(-EPROTO);    /* Corrupted firmware */
2719 
2720     if (use_user) {
2721         /* Take new user parameters */
2722         memcpy(new_setting, user_setting, par_size);
2723     } else if (old_binary_params) {
2724         /* Take previous value */
2725         old_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par,
2726                               par_size,
2727                               old_binary_params);
2728         if (!old_setting)
2729             return ERR_PTR(-EPROTO);
2730         memcpy(new_setting, old_setting, par_size);
2731     } else {
2732         return new_setting; /* Need to calculate */
2733     }
2734 
2735     return NULL;        /* Copied from other value */
2736 }
2737 
2738 /*
2739  * Configure VMEM0 parameters (late binding parameters).
2740  */
2741 int imgu_css_cfg_vmem0(struct imgu_css *css, unsigned int pipe,
2742                struct ipu3_uapi_flags *use,
2743                void *vmem0, void *vmem0_old,
2744                struct ipu3_uapi_params *user)
2745 {
2746     const struct imgu_fw_info *bi =
2747         &css->fwp->binary_header[css->pipes[pipe].bindex];
2748     struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
2749         bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
2750     struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL;
2751     struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem = NULL;
2752     struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem = NULL;
2753     const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2754     const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0;
2755     unsigned int i;
2756 
2757     /* Configure VMEM0 */
2758 
2759     memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
2760 
2761     /* Configure Linearization VMEM0 parameters */
2762 
2763     lin_vmem = imgu_css_cfg_copy(css, pipe, use && use->lin_vmem_params,
2764                      &user->lin_vmem_params, vmem0_old, vmem0,
2765                      m, &pofs->vmem.lin, sizeof(*lin_vmem));
2766     if (!IS_ERR_OR_NULL(lin_vmem)) {
2767         /* Generate parameter from scratch */
2768         for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) {
2769             lin_vmem->lin_lutlow_gr[i] = 32 * i;
2770             lin_vmem->lin_lutlow_r[i] = 32 * i;
2771             lin_vmem->lin_lutlow_b[i] = 32 * i;
2772             lin_vmem->lin_lutlow_gb[i] = 32 * i;
2773 
2774             lin_vmem->lin_lutdif_gr[i] = 32;
2775             lin_vmem->lin_lutdif_r[i] = 32;
2776             lin_vmem->lin_lutdif_b[i] = 32;
2777             lin_vmem->lin_lutdif_gb[i] = 32;
2778         }
2779     }
2780 
2781     /* Configure TNR3 VMEM parameters */
2782     if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
2783         tnr_vmem = imgu_css_cfg_copy(css, pipe,
2784                          use && use->tnr3_vmem_params,
2785                          &user->tnr3_vmem_params,
2786                          vmem0_old, vmem0, m,
2787                          &pofs->vmem.tnr3,
2788                          sizeof(*tnr_vmem));
2789         if (!IS_ERR_OR_NULL(tnr_vmem)) {
2790             /* Generate parameter from scratch */
2791             for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++)
2792                 tnr_vmem->sigma[i] = 256;
2793         }
2794     }
2795     i = IPU3_UAPI_ISP_TNR3_VMEM_LEN;
2796 
2797     /* Configure XNR3 VMEM parameters */
2798 
2799     xnr_vmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params,
2800                      &user->xnr3_vmem_params, vmem0_old, vmem0,
2801                      m, &pofs->vmem.xnr3, sizeof(*xnr_vmem));
2802     if (!IS_ERR_OR_NULL(xnr_vmem)) {
2803         xnr_vmem->x[i] = imgu_css_xnr3_vmem_defaults.x
2804             [i % IMGU_XNR3_VMEM_LUT_LEN];
2805         xnr_vmem->a[i] = imgu_css_xnr3_vmem_defaults.a
2806             [i % IMGU_XNR3_VMEM_LUT_LEN];
2807         xnr_vmem->b[i] = imgu_css_xnr3_vmem_defaults.b
2808             [i % IMGU_XNR3_VMEM_LUT_LEN];
2809         xnr_vmem->c[i] = imgu_css_xnr3_vmem_defaults.c
2810             [i % IMGU_XNR3_VMEM_LUT_LEN];
2811     }
2812 
2813     return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ?
2814         -EPROTO : 0;
2815 }
2816 
2817 /*
2818  * Configure DMEM0 parameters (late binding parameters).
2819  */
2820 int imgu_css_cfg_dmem0(struct imgu_css *css, unsigned int pipe,
2821                struct ipu3_uapi_flags *use,
2822                void *dmem0, void *dmem0_old,
2823                struct ipu3_uapi_params *user)
2824 {
2825     struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
2826     const struct imgu_fw_info *bi =
2827         &css->fwp->binary_header[css_pipe->bindex];
2828     struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
2829         bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
2830 
2831     struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL;
2832     struct ipu3_uapi_isp_xnr3_params *xnr_dmem;
2833 
2834     const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2835     const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0;
2836 
2837     /* Configure DMEM0 */
2838 
2839     memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
2840 
2841     /* Configure TNR3 DMEM0 parameters */
2842     if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
2843         tnr_dmem = imgu_css_cfg_copy(css, pipe,
2844                          use && use->tnr3_dmem_params,
2845                          &user->tnr3_dmem_params,
2846                          dmem0_old, dmem0, m,
2847                          &pofs->dmem.tnr3,
2848                          sizeof(*tnr_dmem));
2849         if (!IS_ERR_OR_NULL(tnr_dmem)) {
2850             /* Generate parameter from scratch */
2851             tnr_dmem->knee_y1 = 768;
2852             tnr_dmem->knee_y2 = 1280;
2853         }
2854     }
2855 
2856     /* Configure XNR3 DMEM0 parameters */
2857 
2858     xnr_dmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params,
2859                      &user->xnr3_dmem_params, dmem0_old, dmem0,
2860                      m, &pofs->dmem.xnr3, sizeof(*xnr_dmem));
2861     if (!IS_ERR_OR_NULL(xnr_dmem)) {
2862         /* Generate parameter from scratch */
2863         xnr_dmem->alpha.y0 = 2047;
2864         xnr_dmem->alpha.u0 = 2047;
2865         xnr_dmem->alpha.v0 = 2047;
2866     }
2867 
2868     return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0;
2869 }
2870 
2871 /* Generate unity morphing table without morphing effect */
2872 void imgu_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc,
2873                 int frame_in_x, int frame_in_y,
2874                 int frame_out_x, int frame_out_y,
2875                 int env_w, int env_h)
2876 {
2877     static const unsigned int FRAC_BITS = IMGU_ABI_GDC_FRAC_BITS;
2878     static const unsigned int XMEM_ALIGN = 1 << 4;
2879     const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1);
2880     static const unsigned int BCI_ENV = 4;
2881     static const unsigned int BYP = 2;  /* Bytes per pixel */
2882     const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + env_w + 1;
2883     const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + env_h + 1;
2884 
2885     struct imgu_abi_gdc_warp_param gdc_luma, gdc_chroma;
2886 
2887     unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x,
2888                            IMGU_DVS_BLOCK_W), 2);
2889     unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H);
2890     unsigned int y0, x0, x1, x, y;
2891 
2892     /* Global luma settings */
2893     gdc_luma.origin_x = 0;
2894     gdc_luma.origin_y = 0;
2895     gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << FRAC_BITS;
2896     gdc_luma.p0_y = 0;
2897     gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
2898     gdc_luma.p1_y = gdc_luma.p0_y;
2899     gdc_luma.p2_x = gdc_luma.p0_x;
2900     gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << FRAC_BITS);
2901     gdc_luma.p3_x = gdc_luma.p1_x;
2902     gdc_luma.p3_y = gdc_luma.p2_y;
2903 
2904     gdc_luma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV +
2905                     OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK);
2906     gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width,
2907                          IPU3_UAPI_ISP_VEC_ELEMS);
2908     gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width,
2909                          IMGU_ABI_ISP_DDR_WORD_BYTES /
2910                          BYP);
2911     gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV;
2912     gdc_luma.padding = 0;
2913 
2914     /* Global chroma settings */
2915     gdc_chroma.origin_x = 0;
2916     gdc_chroma.origin_y = 0;
2917     gdc_chroma.p0_x = (OFFSET_X / 2 - (OFFSET_X / 2 & XMEM_ALIGN_MASK)) <<
2918                FRAC_BITS;
2919     gdc_chroma.p0_y = 0;
2920     gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
2921     gdc_chroma.p1_y = gdc_chroma.p0_y;
2922     gdc_chroma.p2_x = gdc_chroma.p0_x;
2923     gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << FRAC_BITS);
2924     gdc_chroma.p3_x = gdc_chroma.p1_x;
2925     gdc_chroma.p3_y = gdc_chroma.p2_y;
2926 
2927     gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV;
2928     gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width,
2929                            IPU3_UAPI_ISP_VEC_ELEMS);
2930     gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width,
2931                            IMGU_ABI_ISP_DDR_WORD_BYTES /
2932                            BYP);
2933     gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV;
2934     gdc_chroma.padding = 0;
2935 
2936     /* Calculate block offsets for luma and chroma */
2937     for (y0 = 0; y0 < blocks_y; y0++) {
2938         for (x0 = 0; x0 < blocks_x / 2; x0++) {
2939             for (x1 = 0; x1 < 2; x1++) {
2940                 /* Luma blocks */
2941                 x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X;
2942                 x &= XMEM_ALIGN_MASK;
2943                 y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y;
2944                 *gdc = gdc_luma;
2945                 gdc->in_addr_offset =
2946                     (y * frame_in_x + x) * BYP;
2947                 gdc++;
2948             }
2949 
2950             /* Chroma block */
2951             x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2;
2952             x &= XMEM_ALIGN_MASK;
2953             y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2;
2954             *gdc = gdc_chroma;
2955             gdc->in_addr_offset = (y * frame_in_x + x) * BYP;
2956             gdc++;
2957         }
2958     }
2959 }