root/drivers/staging/media/ipu3/ipu3-css-params.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. imgu_css_scaler_get_exp
  2. imgu_css_scaler_setup_lut
  3. imgu_css_scaler_calc_scaled_output
  4. imgu_css_scaler_calc
  5. imgu_css_osys_set_format
  6. imgu_css_osys_calc_stripe_offset
  7. imgu_css_osys_calc_stripe_phase_init
  8. imgu_css_osys_calc_inp_stripe_width
  9. imgu_css_osys_out_stripe_width
  10. imgu_css_osys_calc_frame_and_stripe_params
  11. imgu_css_osys_calc
  12. imgu_css_shd_ops_calc
  13. imgu_css_acc_process_lines
  14. imgu_css_af_ops_calc
  15. imgu_css_awb_fr_ops_calc
  16. imgu_css_awb_ops_calc
  17. imgu_css_grid_end
  18. imgu_css_grid_end_calc
  19. imgu_css_cfg_acc_stripe
  20. imgu_css_cfg_acc_dvs
  21. acc_bds_per_stripe_data
  22. imgu_css_cfg_acc
  23. imgu_css_cfg_copy
  24. imgu_css_cfg_vmem0
  25. imgu_css_cfg_dmem0
  26. imgu_css_cfg_gdc_table

   1 // SPDX-License-Identifier: GPL-2.0
   2 // Copyright (C) 2018 Intel Corporation
   3 
   4 #include <linux/device.h>
   5 
   6 #include "ipu3-css.h"
   7 #include "ipu3-css-fw.h"
   8 #include "ipu3-tables.h"
   9 #include "ipu3-css-params.h"
  10 
  11 #define DIV_ROUND_CLOSEST_DOWN(a, b)    (((a) + ((b) / 2) - 1) / (b))
  12 #define roundclosest_down(a, b)         (DIV_ROUND_CLOSEST_DOWN(a, b) * (b))
  13 
  14 #define IPU3_UAPI_ANR_MAX_RESET         ((1 << 12) - 1)
  15 #define IPU3_UAPI_ANR_MIN_RESET         (((-1) << 12) + 1)
  16 
  17 struct imgu_css_scaler_info {
  18         unsigned int phase_step;        /* Same for luma/chroma */
  19         int exp_shift;
  20 
  21         unsigned int phase_init;        /* luma/chroma dependent */
  22         int pad_left;
  23         int pad_right;
  24         int crop_left;
  25         int crop_top;
  26 };
  27 
  28 static unsigned int imgu_css_scaler_get_exp(unsigned int counter,
  29                                             unsigned int divider)
  30 {
  31         int i = fls(divider) - fls(counter);
  32 
  33         if (i <= 0)
  34                 return 0;
  35 
  36         if (divider >> i < counter)
  37                 i = i - 1;
  38 
  39         return i;
  40 }
  41 
  42 /* Set up the CSS scaler look up table */
  43 static void
  44 imgu_css_scaler_setup_lut(unsigned int taps, unsigned int input_width,
  45                           unsigned int output_width, int phase_step_correction,
  46                           const int *coeffs, unsigned int coeffs_size,
  47                           s8 coeff_lut[], struct imgu_css_scaler_info *info)
  48 {
  49         int tap, phase, phase_sum_left, phase_sum_right;
  50         int exponent = imgu_css_scaler_get_exp(output_width, input_width);
  51         int mantissa = (1 << exponent) * output_width;
  52         unsigned int phase_step;
  53 
  54         if (input_width == output_width) {
  55                 for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
  56                         for (tap = 0; tap < taps; tap++) {
  57                                 coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap]
  58                                         = 0;
  59                         }
  60                 }
  61 
  62                 info->phase_step = IMGU_SCALER_PHASES *
  63                         (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF);
  64                 info->exp_shift = 0;
  65                 info->pad_left = 0;
  66                 info->pad_right = 0;
  67                 info->phase_init = 0;
  68                 info->crop_left = 0;
  69                 info->crop_top = 0;
  70                 return;
  71         }
  72 
  73         for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
  74                 for (tap = 0; tap < taps; tap++) {
  75                         /* flip table to for convolution reverse indexing */
  76                         s64 coeff = coeffs[coeffs_size -
  77                                 ((tap * (coeffs_size / taps)) + phase) - 1];
  78                         coeff *= mantissa;
  79                         coeff = div64_long(coeff, input_width);
  80 
  81                         /* Add +"0.5" */
  82                         coeff += 1 << (IMGU_SCALER_COEFF_BITS - 1);
  83                         coeff >>= IMGU_SCALER_COEFF_BITS;
  84 
  85                         coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap] =
  86                                 coeff;
  87                 }
  88         }
  89 
  90         phase_step = IMGU_SCALER_PHASES *
  91                         (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF) *
  92                         output_width / input_width;
  93         phase_step += phase_step_correction;
  94         phase_sum_left = (taps / 2 * IMGU_SCALER_PHASES *
  95                         (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) -
  96                         (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
  97         phase_sum_right = (taps / 2 * IMGU_SCALER_PHASES *
  98                         (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) +
  99                         (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
 100 
 101         info->exp_shift = IMGU_SCALER_MAX_EXPONENT_SHIFT - exponent;
 102         info->pad_left = (phase_sum_left % phase_step == 0) ?
 103                 phase_sum_left / phase_step - 1 : phase_sum_left / phase_step;
 104         info->pad_right = (phase_sum_right % phase_step == 0) ?
 105                 phase_sum_right / phase_step - 1 : phase_sum_right / phase_step;
 106         info->phase_init = phase_sum_left - phase_step * info->pad_left;
 107         info->phase_step = phase_step;
 108         info->crop_left = taps - 1;
 109         info->crop_top = taps - 1;
 110 }
 111 
 112 /*
 113  * Calculates the exact output image width/height, based on phase_step setting
 114  * (must be perfectly aligned with hardware).
 115  */
 116 static unsigned int
 117 imgu_css_scaler_calc_scaled_output(unsigned int input,
 118                                    struct imgu_css_scaler_info *info)
 119 {
 120         unsigned int arg1 = input * info->phase_step +
 121                         (1 - IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES -
 122                         IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES);
 123         unsigned int arg2 = ((IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES +
 124                         IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES)) *
 125                         IMGU_SCALER_FIR_PHASES + info->phase_step / 2;
 126 
 127         return ((arg1 + (arg2 - IMGU_SCALER_FIR_PHASES * info->phase_step) /
 128                 IMGU_SCALER_FIR_PHASES) / (2 * IMGU_SCALER_FIR_PHASES)) * 2;
 129 }
 130 
 131 /*
 132  * Calculate the output width and height, given the luma
 133  * and chroma details of a scaler
 134  */
 135 static void
 136 imgu_css_scaler_calc(u32 input_width, u32 input_height, u32 target_width,
 137                      u32 target_height, struct imgu_abi_osys_config *cfg,
 138                      struct imgu_css_scaler_info *info_luma,
 139                      struct imgu_css_scaler_info *info_chroma,
 140                      unsigned int *output_width, unsigned int *output_height,
 141                      unsigned int *procmode)
 142 {
 143         u32 out_width = target_width;
 144         u32 out_height = target_height;
 145         const unsigned int height_alignment = 2;
 146         int phase_step_correction = -1;
 147 
 148         /*
 149          * Calculate scaled output width. If the horizontal and vertical scaling
 150          * factor is different, then choose the biggest and crop off excess
 151          * lines or columns after formatting.
 152          */
 153         if (target_height * input_width > target_width * input_height)
 154                 target_width = DIV_ROUND_UP(target_height * input_width,
 155                                             input_height);
 156 
 157         if (input_width == target_width)
 158                 *procmode = IMGU_ABI_OSYS_PROCMODE_BYPASS;
 159         else
 160                 *procmode = IMGU_ABI_OSYS_PROCMODE_DOWNSCALE;
 161 
 162         memset(&cfg->scaler_coeffs_chroma, 0,
 163                sizeof(cfg->scaler_coeffs_chroma));
 164         memset(&cfg->scaler_coeffs_luma, 0, sizeof(*cfg->scaler_coeffs_luma));
 165         do {
 166                 phase_step_correction++;
 167 
 168                 imgu_css_scaler_setup_lut(IMGU_SCALER_TAPS_Y,
 169                                           input_width, target_width,
 170                                           phase_step_correction,
 171                                           imgu_css_downscale_4taps,
 172                                           IMGU_SCALER_DOWNSCALE_4TAPS_LEN,
 173                                           cfg->scaler_coeffs_luma, info_luma);
 174 
 175                 imgu_css_scaler_setup_lut(IMGU_SCALER_TAPS_UV,
 176                                           input_width, target_width,
 177                                           phase_step_correction,
 178                                           imgu_css_downscale_2taps,
 179                                           IMGU_SCALER_DOWNSCALE_2TAPS_LEN,
 180                                           cfg->scaler_coeffs_chroma,
 181                                           info_chroma);
 182 
 183                 out_width = imgu_css_scaler_calc_scaled_output(input_width,
 184                                                                info_luma);
 185                 out_height = imgu_css_scaler_calc_scaled_output(input_height,
 186                                                                 info_luma);
 187         } while ((out_width < target_width || out_height < target_height ||
 188                  !IS_ALIGNED(out_height, height_alignment)) &&
 189                  phase_step_correction <= 5);
 190 
 191         *output_width = out_width;
 192         *output_height = out_height;
 193 }
 194 
 195 /********************** Osys routines for scaler****************************/
 196 
 197 static void imgu_css_osys_set_format(enum imgu_abi_frame_format host_format,
 198                                      unsigned int *osys_format,
 199                                      unsigned int *osys_tiling)
 200 {
 201         *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
 202         *osys_tiling = IMGU_ABI_OSYS_TILING_NONE;
 203 
 204         switch (host_format) {
 205         case IMGU_ABI_FRAME_FORMAT_YUV420:
 206                 *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
 207                 break;
 208         case IMGU_ABI_FRAME_FORMAT_YV12:
 209                 *osys_format = IMGU_ABI_OSYS_FORMAT_YV12;
 210                 break;
 211         case IMGU_ABI_FRAME_FORMAT_NV12:
 212                 *osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
 213                 break;
 214         case IMGU_ABI_FRAME_FORMAT_NV16:
 215                 *osys_format = IMGU_ABI_OSYS_FORMAT_NV16;
 216                 break;
 217         case IMGU_ABI_FRAME_FORMAT_NV21:
 218                 *osys_format = IMGU_ABI_OSYS_FORMAT_NV21;
 219                 break;
 220         case IMGU_ABI_FRAME_FORMAT_NV12_TILEY:
 221                 *osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
 222                 *osys_tiling = IMGU_ABI_OSYS_TILING_Y;
 223                 break;
 224         default:
 225                 /* For now, assume use default values */
 226                 break;
 227         }
 228 }
 229 
 230 /*
 231  * Function calculates input frame stripe offset, based
 232  * on output frame stripe offset and filter parameters.
 233  */
 234 static int imgu_css_osys_calc_stripe_offset(int stripe_offset_out,
 235                                             int fir_phases, int phase_init,
 236                                             int phase_step, int pad_left)
 237 {
 238         int stripe_offset_inp = stripe_offset_out * fir_phases -
 239                                 pad_left * phase_step;
 240 
 241         return DIV_ROUND_UP(stripe_offset_inp - phase_init, phase_step);
 242 }
 243 
 244 /*
 245  * Calculate input frame phase, given the output frame
 246  * stripe offset and filter parameters
 247  */
 248 static int imgu_css_osys_calc_stripe_phase_init(int stripe_offset_out,
 249                                                 int fir_phases, int phase_init,
 250                                                 int phase_step, int pad_left)
 251 {
 252         int stripe_offset_inp =
 253                 imgu_css_osys_calc_stripe_offset(stripe_offset_out,
 254                                                  fir_phases, phase_init,
 255                                                  phase_step, pad_left);
 256 
 257         return phase_init + ((pad_left + stripe_offset_inp) * phase_step) -
 258                 stripe_offset_out * fir_phases;
 259 }
 260 
 261 /*
 262  * This function calculates input frame stripe width,
 263  * based on output frame stripe offset and filter parameters
 264  */
 265 static int imgu_css_osys_calc_inp_stripe_width(int stripe_width_out,
 266                                                int fir_phases, int phase_init,
 267                                                int phase_step, int fir_taps,
 268                                                int pad_left, int pad_right)
 269 {
 270         int stripe_width_inp = (stripe_width_out + fir_taps - 1) * fir_phases;
 271 
 272         stripe_width_inp = DIV_ROUND_UP(stripe_width_inp - phase_init,
 273                                         phase_step);
 274 
 275         return stripe_width_inp - pad_left - pad_right;
 276 }
 277 
 278 /*
 279  * This function calculates output frame stripe width, basedi
 280  * on output frame stripe offset and filter parameters
 281  */
 282 static int imgu_css_osys_out_stripe_width(int stripe_width_inp, int fir_phases,
 283                                           int phase_init, int phase_step,
 284                                           int fir_taps, int pad_left,
 285                                           int pad_right, int column_offset)
 286 {
 287         int stripe_width_out = (pad_left + stripe_width_inp +
 288                                 pad_right - column_offset) * phase_step;
 289 
 290         stripe_width_out = (stripe_width_out + phase_init) / fir_phases;
 291 
 292         return stripe_width_out - (fir_taps - 1);
 293 }
 294 
 295 struct imgu_css_reso {
 296         unsigned int input_width;
 297         unsigned int input_height;
 298         enum imgu_abi_frame_format input_format;
 299         unsigned int pin_width[IMGU_ABI_OSYS_PINS];
 300         unsigned int pin_height[IMGU_ABI_OSYS_PINS];
 301         unsigned int pin_stride[IMGU_ABI_OSYS_PINS];
 302         enum imgu_abi_frame_format pin_format[IMGU_ABI_OSYS_PINS];
 303         int chunk_width;
 304         int chunk_height;
 305         int block_height;
 306         int block_width;
 307 };
 308 
 309 struct imgu_css_frame_params {
 310         /* Output pins */
 311         unsigned int enable;
 312         unsigned int format;
 313         unsigned int flip;
 314         unsigned int mirror;
 315         unsigned int tiling;
 316         unsigned int reduce_range;
 317         unsigned int width;
 318         unsigned int height;
 319         unsigned int stride;
 320         unsigned int scaled;
 321         unsigned int crop_left;
 322         unsigned int crop_top;
 323 };
 324 
 325 struct imgu_css_stripe_params {
 326         unsigned int processing_mode;
 327         unsigned int phase_step;
 328         unsigned int exp_shift;
 329         unsigned int phase_init_left_y;
 330         unsigned int phase_init_left_uv;
 331         unsigned int phase_init_top_y;
 332         unsigned int phase_init_top_uv;
 333         unsigned int pad_left_y;
 334         unsigned int pad_left_uv;
 335         unsigned int pad_right_y;
 336         unsigned int pad_right_uv;
 337         unsigned int pad_top_y;
 338         unsigned int pad_top_uv;
 339         unsigned int pad_bottom_y;
 340         unsigned int pad_bottom_uv;
 341         unsigned int crop_left_y;
 342         unsigned int crop_top_y;
 343         unsigned int crop_left_uv;
 344         unsigned int crop_top_uv;
 345         unsigned int start_column_y;
 346         unsigned int start_column_uv;
 347         unsigned int chunk_width;
 348         unsigned int chunk_height;
 349         unsigned int block_width;
 350         unsigned int block_height;
 351         unsigned int input_width;
 352         unsigned int input_height;
 353         int output_width[IMGU_ABI_OSYS_PINS];
 354         int output_height[IMGU_ABI_OSYS_PINS];
 355         int output_offset[IMGU_ABI_OSYS_PINS];
 356 };
 357 
 358 /*
 359  * frame_params - size IMGU_ABI_OSYS_PINS
 360  * stripe_params - size IPU3_UAPI_MAX_STRIPES
 361  */
 362 static int imgu_css_osys_calc_frame_and_stripe_params(
 363                 struct imgu_css *css, unsigned int stripes,
 364                 struct imgu_abi_osys_config *osys,
 365                 struct imgu_css_scaler_info *scaler_luma,
 366                 struct imgu_css_scaler_info *scaler_chroma,
 367                 struct imgu_css_frame_params frame_params[],
 368                 struct imgu_css_stripe_params stripe_params[],
 369                 unsigned int pipe)
 370 {
 371         struct imgu_css_reso reso;
 372         unsigned int output_width, pin, s;
 373         u32 input_width, input_height, target_width, target_height;
 374         unsigned int procmode = 0;
 375         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
 376 
 377         input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
 378         input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
 379         target_width = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
 380         target_height = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
 381 
 382         /* Frame parameters */
 383 
 384         /* Input width for Output System is output width of DVS (with GDC) */
 385         reso.input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width;
 386 
 387         /* Input height for Output System is output height of DVS (with GDC) */
 388         reso.input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
 389 
 390         reso.input_format =
 391                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
 392 
 393         reso.pin_width[IMGU_ABI_OSYS_PIN_OUT] =
 394                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
 395         reso.pin_height[IMGU_ABI_OSYS_PIN_OUT] =
 396                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
 397         reso.pin_stride[IMGU_ABI_OSYS_PIN_OUT] =
 398                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad;
 399         reso.pin_format[IMGU_ABI_OSYS_PIN_OUT] =
 400                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
 401 
 402         reso.pin_width[IMGU_ABI_OSYS_PIN_VF] =
 403                 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
 404         reso.pin_height[IMGU_ABI_OSYS_PIN_VF] =
 405                 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
 406         reso.pin_stride[IMGU_ABI_OSYS_PIN_VF] =
 407                 css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad;
 408         reso.pin_format[IMGU_ABI_OSYS_PIN_VF] =
 409                 css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
 410 
 411         /* Configure the frame parameters for all output pins */
 412 
 413         frame_params[IMGU_ABI_OSYS_PIN_OUT].width =
 414                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
 415         frame_params[IMGU_ABI_OSYS_PIN_OUT].height =
 416                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
 417         frame_params[IMGU_ABI_OSYS_PIN_VF].width =
 418                 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
 419         frame_params[IMGU_ABI_OSYS_PIN_VF].height =
 420                 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
 421         frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 0;
 422         frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 0;
 423 
 424         for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
 425                 int enable = 0;
 426                 int scaled = 0;
 427                 unsigned int format = 0;
 428                 unsigned int tiling = 0;
 429 
 430                 frame_params[pin].flip = 0;
 431                 frame_params[pin].mirror = 0;
 432                 frame_params[pin].reduce_range = 0;
 433                 if (reso.pin_width[pin] != 0 && reso.pin_height[pin] != 0) {
 434                         enable = 1;
 435                         if (pin == IMGU_ABI_OSYS_PIN_OUT) {
 436                                 if (reso.input_width < reso.pin_width[pin] ||
 437                                     reso.input_height < reso.pin_height[pin])
 438                                         return -EINVAL;
 439                                 /*
 440                                  * When input and output resolution is
 441                                  * different instead of scaling, cropping
 442                                  * should happen. Determine the crop factor
 443                                  * to do the symmetric cropping
 444                                  */
 445                                 frame_params[pin].crop_left = roundclosest_down(
 446                                                 (reso.input_width -
 447                                                  reso.pin_width[pin]) / 2,
 448                                                  IMGU_OSYS_DMA_CROP_W_LIMIT);
 449                                 frame_params[pin].crop_top = roundclosest_down(
 450                                                 (reso.input_height -
 451                                                  reso.pin_height[pin]) / 2,
 452                                                  IMGU_OSYS_DMA_CROP_H_LIMIT);
 453                         } else {
 454                                 if (reso.pin_width[pin] != reso.input_width ||
 455                                     reso.pin_height[pin] != reso.input_height) {
 456                                         /*
 457                                          * If resolution is different at input
 458                                          * and output of OSYS, scaling is
 459                                          * considered except when pin is MAIN.
 460                                          * Later it will be decide whether
 461                                          * scaler factor is 1 or other
 462                                          * and cropping has to be done or not.
 463                                          */
 464                                         scaled = 1;
 465                                 }
 466                         }
 467                         imgu_css_osys_set_format(reso.pin_format[pin], &format,
 468                                                  &tiling);
 469                 } else {
 470                         enable = 0;
 471                 }
 472                 frame_params[pin].enable = enable;
 473                 frame_params[pin].format = format;
 474                 frame_params[pin].tiling = tiling;
 475                 frame_params[pin].stride = reso.pin_stride[pin];
 476                 frame_params[pin].scaled = scaled;
 477         }
 478 
 479         imgu_css_scaler_calc(input_width, input_height, target_width,
 480                              target_height, osys, scaler_luma, scaler_chroma,
 481                              &reso.pin_width[IMGU_ABI_OSYS_PIN_VF],
 482                              &reso.pin_height[IMGU_ABI_OSYS_PIN_VF], &procmode);
 483         dev_dbg(css->dev, "osys scaler procmode is %u", procmode);
 484         output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
 485 
 486         if (output_width < reso.input_width / 2) {
 487                 /* Scaling factor <= 0.5 */
 488                 reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH;
 489                 reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
 490         } else { /* 0.5 <= Scaling factor <= 1.0 */
 491                 reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH / 2;
 492                 reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
 493         }
 494 
 495         if (output_width <= reso.input_width * 7 / 8) {
 496                 /* Scaling factor <= 0.875 */
 497                 reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT;
 498                 reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
 499         } else { /* 1.0 <= Scaling factor <= 1.75 */
 500                 reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT / 2;
 501                 reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
 502         }
 503 
 504         /*
 505          * Calculate scaler configuration parameters based on input and output
 506          * resolution.
 507          */
 508 
 509         if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
 510                 /*
 511                  * When aspect ratio is different between target resolution and
 512                  * required resolution, determine the crop factor to do
 513                  * symmetric cropping
 514                  */
 515                 u32 w = reso.pin_width[IMGU_ABI_OSYS_PIN_VF] -
 516                         frame_params[IMGU_ABI_OSYS_PIN_VF].width;
 517                 u32 h = reso.pin_height[IMGU_ABI_OSYS_PIN_VF] -
 518                         frame_params[IMGU_ABI_OSYS_PIN_VF].height;
 519 
 520                 frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left =
 521                         roundclosest_down(w / 2, IMGU_OSYS_DMA_CROP_W_LIMIT);
 522                 frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top =
 523                         roundclosest_down(h / 2, IMGU_OSYS_DMA_CROP_H_LIMIT);
 524 
 525                 if (reso.input_height % 4 || reso.input_width % 8) {
 526                         dev_err(css->dev, "OSYS input width is not multiple of 8 or\n");
 527                         dev_err(css->dev, "height is not multiple of 4\n");
 528                         return -EINVAL;
 529                 }
 530         }
 531 
 532         /* Stripe parameters */
 533 
 534         if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
 535                 output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
 536         } else {
 537                 /*
 538                  * in case scaler output is not enabled
 539                  * take output width as input width since
 540                  * there is no scaling at main pin.
 541                  * Due to the fact that main pin can be different
 542                  * from input resolution to osys in the case of cropping,
 543                  * main pin resolution is not taken.
 544                  */
 545                 output_width = reso.input_width;
 546         }
 547 
 548         for (s = 0; s < stripes; s++) {
 549                 int stripe_offset_inp_y = 0;
 550                 int stripe_offset_inp_uv = 0;
 551                 int stripe_offset_out_y = 0;
 552                 int stripe_offset_out_uv = 0;
 553                 int stripe_phase_init_y = scaler_luma->phase_init;
 554                 int stripe_phase_init_uv = scaler_chroma->phase_init;
 555                 int stripe_offset_blk_y = 0;
 556                 int stripe_offset_blk_uv = 0;
 557                 int stripe_offset_col_y = 0;
 558                 int stripe_offset_col_uv = 0;
 559                 int stripe_pad_left_y = scaler_luma->pad_left;
 560                 int stripe_pad_left_uv = scaler_chroma->pad_left;
 561                 int stripe_pad_right_y = scaler_luma->pad_right;
 562                 int stripe_pad_right_uv = scaler_chroma->pad_right;
 563                 int stripe_crop_left_y = scaler_luma->crop_left;
 564                 int stripe_crop_left_uv = scaler_chroma->crop_left;
 565                 int stripe_input_width_y = reso.input_width;
 566                 int stripe_input_width_uv = 0;
 567                 int stripe_output_width_y = output_width;
 568                 int stripe_output_width_uv = 0;
 569                 int chunk_floor_y = 0;
 570                 int chunk_floor_uv = 0;
 571                 int chunk_ceil_uv = 0;
 572 
 573                 if (stripes > 1) {
 574                         if (s > 0) {
 575                                 /* Calculate stripe offsets */
 576                                 stripe_offset_out_y =
 577                                         output_width * s / stripes;
 578                                 stripe_offset_out_y =
 579                                         rounddown(stripe_offset_out_y,
 580                                                   IPU3_UAPI_ISP_VEC_ELEMS);
 581                                 stripe_offset_out_uv = stripe_offset_out_y /
 582                                                 IMGU_LUMA_TO_CHROMA_RATIO;
 583                                 stripe_offset_inp_y =
 584                                         imgu_css_osys_calc_stripe_offset(
 585                                                 stripe_offset_out_y,
 586                                                 IMGU_OSYS_FIR_PHASES,
 587                                                 scaler_luma->phase_init,
 588                                                 scaler_luma->phase_step,
 589                                                 scaler_luma->pad_left);
 590                                 stripe_offset_inp_uv =
 591                                         imgu_css_osys_calc_stripe_offset(
 592                                                 stripe_offset_out_uv,
 593                                                 IMGU_OSYS_FIR_PHASES,
 594                                                 scaler_chroma->phase_init,
 595                                                 scaler_chroma->phase_step,
 596                                                 scaler_chroma->pad_left);
 597 
 598                                 /* Calculate stripe phase init */
 599                                 stripe_phase_init_y =
 600                                         imgu_css_osys_calc_stripe_phase_init(
 601                                                 stripe_offset_out_y,
 602                                                 IMGU_OSYS_FIR_PHASES,
 603                                                 scaler_luma->phase_init,
 604                                                 scaler_luma->phase_step,
 605                                                 scaler_luma->pad_left);
 606                                 stripe_phase_init_uv =
 607                                         imgu_css_osys_calc_stripe_phase_init(
 608                                                 stripe_offset_out_uv,
 609                                                 IMGU_OSYS_FIR_PHASES,
 610                                                 scaler_chroma->phase_init,
 611                                                 scaler_chroma->phase_step,
 612                                                 scaler_chroma->pad_left);
 613 
 614                                 /*
 615                                  * Chunk boundary corner case - luma and chroma
 616                                  * start from different input chunks.
 617                                  */
 618                                 chunk_floor_y = rounddown(stripe_offset_inp_y,
 619                                                           reso.chunk_width);
 620                                 chunk_floor_uv =
 621                                         rounddown(stripe_offset_inp_uv,
 622                                                   reso.chunk_width /
 623                                                   IMGU_LUMA_TO_CHROMA_RATIO);
 624 
 625                                 if (chunk_floor_y != chunk_floor_uv *
 626                                     IMGU_LUMA_TO_CHROMA_RATIO) {
 627                                         /*
 628                                          * Match starting luma/chroma chunks.
 629                                          * Decrease offset for UV and add output
 630                                          * cropping.
 631                                          */
 632                                         stripe_offset_inp_uv -= 1;
 633                                         stripe_crop_left_uv += 1;
 634                                         stripe_phase_init_uv -=
 635                                                 scaler_luma->phase_step;
 636                                         if (stripe_phase_init_uv < 0)
 637                                                 stripe_phase_init_uv =
 638                                                         stripe_phase_init_uv +
 639                                                         IMGU_OSYS_FIR_PHASES;
 640                                 }
 641                                 /*
 642                                  * FW workaround for a HW bug: if the first
 643                                  * chroma pixel is generated exactly at the end
 644                                  * of chunck scaler HW may not output the pixel
 645                                  * for downscale factors smaller than 1.5
 646                                  * (timing issue).
 647                                  */
 648                                 chunk_ceil_uv =
 649                                         roundup(stripe_offset_inp_uv,
 650                                                 reso.chunk_width /
 651                                                 IMGU_LUMA_TO_CHROMA_RATIO);
 652 
 653                                 if (stripe_offset_inp_uv ==
 654                                     chunk_ceil_uv - IMGU_OSYS_TAPS_UV) {
 655                                         /*
 656                                          * Decrease input offset and add
 657                                          * output cropping
 658                                          */
 659                                         stripe_offset_inp_uv -= 1;
 660                                         stripe_phase_init_uv -=
 661                                                 scaler_luma->phase_step;
 662                                         if (stripe_phase_init_uv < 0) {
 663                                                 stripe_phase_init_uv +=
 664                                                         IMGU_OSYS_FIR_PHASES;
 665                                                 stripe_crop_left_uv += 1;
 666                                         }
 667                                 }
 668 
 669                                 /*
 670                                  * Calculate block and column offsets for the
 671                                  * input stripe
 672                                  */
 673                                 stripe_offset_blk_y =
 674                                         rounddown(stripe_offset_inp_y,
 675                                                   IMGU_INPUT_BLOCK_WIDTH);
 676                                 stripe_offset_blk_uv =
 677                                         rounddown(stripe_offset_inp_uv,
 678                                                   IMGU_INPUT_BLOCK_WIDTH /
 679                                                   IMGU_LUMA_TO_CHROMA_RATIO);
 680                                 stripe_offset_col_y = stripe_offset_inp_y -
 681                                                         stripe_offset_blk_y;
 682                                 stripe_offset_col_uv = stripe_offset_inp_uv -
 683                                                         stripe_offset_blk_uv;
 684 
 685                                 /* Left padding is only for the first stripe */
 686                                 stripe_pad_left_y = 0;
 687                                 stripe_pad_left_uv = 0;
 688                         }
 689 
 690                         /* Right padding is only for the last stripe */
 691                         if (s < stripes - 1) {
 692                                 int next_offset;
 693 
 694                                 stripe_pad_right_y = 0;
 695                                 stripe_pad_right_uv = 0;
 696 
 697                                 next_offset = output_width * (s + 1) / stripes;
 698                                 next_offset = rounddown(next_offset, 64);
 699                                 stripe_output_width_y = next_offset -
 700                                                         stripe_offset_out_y;
 701                         } else {
 702                                 stripe_output_width_y = output_width -
 703                                                         stripe_offset_out_y;
 704                         }
 705 
 706                         /* Calculate target output stripe width */
 707                         stripe_output_width_uv = stripe_output_width_y /
 708                                                 IMGU_LUMA_TO_CHROMA_RATIO;
 709                         /* Calculate input stripe width */
 710                         stripe_input_width_y = stripe_offset_col_y +
 711                                 imgu_css_osys_calc_inp_stripe_width(
 712                                                 stripe_output_width_y,
 713                                                 IMGU_OSYS_FIR_PHASES,
 714                                                 stripe_phase_init_y,
 715                                                 scaler_luma->phase_step,
 716                                                 IMGU_OSYS_TAPS_Y,
 717                                                 stripe_pad_left_y,
 718                                                 stripe_pad_right_y);
 719 
 720                         stripe_input_width_uv = stripe_offset_col_uv +
 721                                 imgu_css_osys_calc_inp_stripe_width(
 722                                                 stripe_output_width_uv,
 723                                                 IMGU_OSYS_FIR_PHASES,
 724                                                 stripe_phase_init_uv,
 725                                                 scaler_chroma->phase_step,
 726                                                 IMGU_OSYS_TAPS_UV,
 727                                                 stripe_pad_left_uv,
 728                                                 stripe_pad_right_uv);
 729 
 730                         stripe_input_width_uv = max(DIV_ROUND_UP(
 731                                                     stripe_input_width_y,
 732                                                     IMGU_LUMA_TO_CHROMA_RATIO),
 733                                                     stripe_input_width_uv);
 734 
 735                         stripe_input_width_y = stripe_input_width_uv *
 736                                                 IMGU_LUMA_TO_CHROMA_RATIO;
 737 
 738                         if (s >= stripes - 1) {
 739                                 stripe_input_width_y = reso.input_width -
 740                                         stripe_offset_blk_y;
 741                                 /*
 742                                  * The scaler requires that the last stripe
 743                                  * spans at least two input blocks.
 744                                  */
 745                         }
 746 
 747                         /*
 748                          * Spec: input stripe width must be a multiple of 8.
 749                          * Increase the input width and recalculate the output
 750                          * width. This may produce an extra column of junk
 751                          * blocks which will be overwritten by the
 752                          * next stripe.
 753                          */
 754                         stripe_input_width_y = ALIGN(stripe_input_width_y, 8);
 755                         stripe_output_width_y =
 756                                 imgu_css_osys_out_stripe_width(
 757                                                 stripe_input_width_y,
 758                                                 IMGU_OSYS_FIR_PHASES,
 759                                                 stripe_phase_init_y,
 760                                                 scaler_luma->phase_step,
 761                                                 IMGU_OSYS_TAPS_Y,
 762                                                 stripe_pad_left_y,
 763                                                 stripe_pad_right_y,
 764                                                 stripe_offset_col_y);
 765 
 766                         stripe_output_width_y =
 767                                         rounddown(stripe_output_width_y,
 768                                                   IMGU_LUMA_TO_CHROMA_RATIO);
 769                 }
 770                 /*
 771                  * Following section executes and process parameters
 772                  * for both cases - Striping or No Striping.
 773                  */
 774                 {
 775                         unsigned int i;
 776                         int pin_scale = 0;
 777                         /*Input resolution */
 778 
 779                         stripe_params[s].input_width = stripe_input_width_y;
 780                         stripe_params[s].input_height = reso.input_height;
 781 
 782                         for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) {
 783                                 if (frame_params[i].scaled) {
 784                                         /*
 785                                          * Output stripe resolution and offset
 786                                          * as produced by the scaler; actual
 787                                          * output resolution may be slightly
 788                                          * smaller.
 789                                          */
 790                                         stripe_params[s].output_width[i] =
 791                                                 stripe_output_width_y;
 792                                         stripe_params[s].output_height[i] =
 793                                                 reso.pin_height[i];
 794                                         stripe_params[s].output_offset[i] =
 795                                                 stripe_offset_out_y;
 796 
 797                                         pin_scale += frame_params[i].scaled;
 798                                 } else {
 799                                         /* Unscaled pin */
 800                                         stripe_params[s].output_width[i] =
 801                                                 stripe_params[s].input_width;
 802                                         stripe_params[s].output_height[i] =
 803                                                 stripe_params[s].input_height;
 804                                         stripe_params[s].output_offset[i] =
 805                                                 stripe_offset_blk_y;
 806                                 }
 807                         }
 808 
 809                         /* If no pin use scale, we use BYPASS mode */
 810                         stripe_params[s].processing_mode = procmode;
 811                         stripe_params[s].phase_step = scaler_luma->phase_step;
 812                         stripe_params[s].exp_shift = scaler_luma->exp_shift;
 813                         stripe_params[s].phase_init_left_y =
 814                                 stripe_phase_init_y;
 815                         stripe_params[s].phase_init_left_uv =
 816                                 stripe_phase_init_uv;
 817                         stripe_params[s].phase_init_top_y =
 818                                 scaler_luma->phase_init;
 819                         stripe_params[s].phase_init_top_uv =
 820                                 scaler_chroma->phase_init;
 821                         stripe_params[s].pad_left_y = stripe_pad_left_y;
 822                         stripe_params[s].pad_left_uv = stripe_pad_left_uv;
 823                         stripe_params[s].pad_right_y = stripe_pad_right_y;
 824                         stripe_params[s].pad_right_uv = stripe_pad_right_uv;
 825                         stripe_params[s].pad_top_y = scaler_luma->pad_left;
 826                         stripe_params[s].pad_top_uv = scaler_chroma->pad_left;
 827                         stripe_params[s].pad_bottom_y = scaler_luma->pad_right;
 828                         stripe_params[s].pad_bottom_uv =
 829                                 scaler_chroma->pad_right;
 830                         stripe_params[s].crop_left_y = stripe_crop_left_y;
 831                         stripe_params[s].crop_top_y = scaler_luma->crop_top;
 832                         stripe_params[s].crop_left_uv = stripe_crop_left_uv;
 833                         stripe_params[s].crop_top_uv = scaler_chroma->crop_top;
 834                         stripe_params[s].start_column_y = stripe_offset_col_y;
 835                         stripe_params[s].start_column_uv = stripe_offset_col_uv;
 836                         stripe_params[s].chunk_width = reso.chunk_width;
 837                         stripe_params[s].chunk_height = reso.chunk_height;
 838                         stripe_params[s].block_width = reso.block_width;
 839                         stripe_params[s].block_height = reso.block_height;
 840                 }
 841         }
 842 
 843         return 0;
 844 }
 845 
 846 /*
 847  * This function configures the Output Formatter System, given the number of
 848  * stripes, scaler luma and chrome parameters
 849  */
 850 static int imgu_css_osys_calc(struct imgu_css *css, unsigned int pipe,
 851                               unsigned int stripes,
 852                               struct imgu_abi_osys_config *osys,
 853                               struct imgu_css_scaler_info *scaler_luma,
 854                               struct imgu_css_scaler_info *scaler_chroma,
 855                               struct imgu_abi_stripes block_stripes[])
 856 {
 857         struct imgu_css_frame_params frame_params[IMGU_ABI_OSYS_PINS];
 858         struct imgu_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES];
 859         struct imgu_abi_osys_formatter_params *param;
 860         unsigned int pin, s;
 861         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
 862 
 863         memset(osys, 0, sizeof(*osys));
 864 
 865         /* Compute the frame and stripe params */
 866         if (imgu_css_osys_calc_frame_and_stripe_params(css, stripes, osys,
 867                                                        scaler_luma,
 868                                                        scaler_chroma,
 869                                                        frame_params,
 870                                                        stripe_params, pipe))
 871                 return -EINVAL;
 872 
 873         /* Output formatter system parameters */
 874 
 875         for (s = 0; s < stripes; s++) {
 876                 struct imgu_abi_osys_scaler_params *scaler =
 877                                         &osys->scaler[s].param;
 878                 int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT;
 879                 int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP;
 880 
 881                 /* OUTPUT 0 / PIN 0 is only Scaler output */
 882                 scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
 883 
 884                 /*
 885                  * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
 886                  * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) /
 887                  *   (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
 888                  * = 2 * 64 / 32 = 4
 889                  */
 890                 scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE;
 891                 /*
 892                  * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size)
 893                  * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) +
 894                  *      (VMEM1_y_size / 4)
 895                  * = (VMEM1_y_size) + (VMEM1_y_size / 4) +
 896                  * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4
 897                  * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
 898                  */
 899                 scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
 900                 scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
 901                                                 IMGU_VMEM1_U_OFFSET;
 902                 scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
 903                                                 IMGU_VMEM1_V_OFFSET;
 904                 scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE;
 905                 scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
 906                 scaler->inp_buf_chunk_width = stripe_params[s].chunk_width;
 907                 scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS;
 908 
 909                 /* Output buffers */
 910                 scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
 911                 scaler->out_buf_y_line_stride = stripe_params[s].block_width /
 912                                                 IMGU_VMEM1_ELEMS_PER_VEC;
 913                 scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
 914                 scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
 915                                                 IMGU_VMEM1_U_OFFSET;
 916                 scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
 917                                                 IMGU_VMEM1_V_OFFSET;
 918                 scaler->out_buf_uv_line_stride = stripe_params[s].block_width /
 919                                                 IMGU_VMEM1_ELEMS_PER_VEC / 2;
 920                 scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
 921                 scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS;
 922 
 923                 /* Intermediate buffers */
 924                 scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR;
 925                 scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE;
 926                 scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR;
 927                 scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR;
 928                 scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE;
 929                 scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK;
 930                 scaler->int_buf_chunk_width = stripe_params[s].chunk_height;
 931                 scaler->int_buf_chunk_height = stripe_params[s].block_width;
 932 
 933                 /* Context buffers */
 934                 scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR;
 935                 scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR;
 936                 scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR;
 937                 scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR;
 938                 scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR;
 939                 scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR;
 940 
 941                 /* Addresses for release-input and process-output tokens */
 942                 scaler->release_inp_buf_addr = fifo_addr_ack;
 943                 scaler->release_inp_buf_en = 1;
 944                 scaler->release_out_buf_en = 1;
 945                 scaler->process_out_buf_addr = fifo_addr_fmt;
 946 
 947                 /* Settings dimensions, padding, cropping */
 948                 scaler->input_image_y_width = stripe_params[s].input_width;
 949                 scaler->input_image_y_height = stripe_params[s].input_height;
 950                 scaler->input_image_y_start_column =
 951                                         stripe_params[s].start_column_y;
 952                 scaler->input_image_uv_start_column =
 953                                         stripe_params[s].start_column_uv;
 954                 scaler->input_image_y_left_pad = stripe_params[s].pad_left_y;
 955                 scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv;
 956                 scaler->input_image_y_right_pad = stripe_params[s].pad_right_y;
 957                 scaler->input_image_uv_right_pad =
 958                                         stripe_params[s].pad_right_uv;
 959                 scaler->input_image_y_top_pad = stripe_params[s].pad_top_y;
 960                 scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv;
 961                 scaler->input_image_y_bottom_pad =
 962                                         stripe_params[s].pad_bottom_y;
 963                 scaler->input_image_uv_bottom_pad =
 964                                         stripe_params[s].pad_bottom_uv;
 965                 scaler->processing_mode = stripe_params[s].processing_mode;
 966                 scaler->scaling_ratio = stripe_params[s].phase_step;
 967                 scaler->y_left_phase_init = stripe_params[s].phase_init_left_y;
 968                 scaler->uv_left_phase_init =
 969                                         stripe_params[s].phase_init_left_uv;
 970                 scaler->y_top_phase_init = stripe_params[s].phase_init_top_y;
 971                 scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv;
 972                 scaler->coeffs_exp_shift = stripe_params[s].exp_shift;
 973                 scaler->out_y_left_crop = stripe_params[s].crop_left_y;
 974                 scaler->out_uv_left_crop = stripe_params[s].crop_left_uv;
 975                 scaler->out_y_top_crop = stripe_params[s].crop_top_y;
 976                 scaler->out_uv_top_crop = stripe_params[s].crop_top_uv;
 977 
 978                 for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
 979                         int in_fifo_addr;
 980                         int out_fifo_addr;
 981                         int block_width_vecs;
 982                         int input_width_s;
 983                         int input_width_vecs;
 984                         int input_buf_y_st_addr;
 985                         int input_buf_u_st_addr;
 986                         int input_buf_v_st_addr;
 987                         int input_buf_y_line_stride;
 988                         int input_buf_uv_line_stride;
 989                         int output_buf_y_line_stride;
 990                         int output_buf_uv_line_stride;
 991                         int output_buf_nr_y_lines;
 992                         int block_height;
 993                         int block_width;
 994                         struct imgu_abi_osys_frame_params *fr_pr;
 995 
 996                         fr_pr = &osys->frame[pin].param;
 997 
 998                         /* Frame parameters */
 999                         fr_pr->enable = frame_params[pin].enable;
1000                         fr_pr->format = frame_params[pin].format;
1001                         fr_pr->mirror = frame_params[pin].mirror;
1002                         fr_pr->flip = frame_params[pin].flip;
1003                         fr_pr->tiling = frame_params[pin].tiling;
1004                         fr_pr->width = frame_params[pin].width;
1005                         fr_pr->height = frame_params[pin].height;
1006                         fr_pr->stride = frame_params[pin].stride;
1007                         fr_pr->scaled = frame_params[pin].scaled;
1008 
1009                         /* Stripe parameters */
1010                         osys->stripe[s].crop_top[pin] =
1011                                 frame_params[pin].crop_top;
1012                         osys->stripe[s].input_width =
1013                                 stripe_params[s].input_width;
1014                         osys->stripe[s].input_height =
1015                                 stripe_params[s].input_height;
1016                         osys->stripe[s].block_height =
1017                                 stripe_params[s].block_height;
1018                         osys->stripe[s].block_width =
1019                                 stripe_params[s].block_width;
1020                         osys->stripe[s].output_width[pin] =
1021                                 stripe_params[s].output_width[pin];
1022                         osys->stripe[s].output_height[pin] =
1023                                 stripe_params[s].output_height[pin];
1024 
1025                         if (s == 0) {
1026                                 /* Only first stripe should do left cropping */
1027                                 osys->stripe[s].crop_left[pin] =
1028                                         frame_params[pin].crop_left;
1029                                 osys->stripe[s].output_offset[pin] =
1030                                         stripe_params[s].output_offset[pin];
1031                         } else {
1032                                 /*
1033                                  * Stripe offset for other strips should be
1034                                  * adjusted according to the cropping done
1035                                  * at the first strip
1036                                  */
1037                                 osys->stripe[s].crop_left[pin] = 0;
1038                                 osys->stripe[s].output_offset[pin] =
1039                                         (stripe_params[s].output_offset[pin] -
1040                                          osys->stripe[0].crop_left[pin]);
1041                         }
1042 
1043                         if (!frame_params[pin].enable)
1044                                 continue;
1045 
1046                         /* Formatter: configurations */
1047 
1048                         /*
1049                          * Get the dimensions of the input blocks of the
1050                          * formatter, which is the same as the output
1051                          * blocks of the scaler.
1052                          */
1053                         if (frame_params[pin].scaled) {
1054                                 block_height = stripe_params[s].block_height;
1055                                 block_width = stripe_params[s].block_width;
1056                         } else {
1057                                 block_height = IMGU_OSYS_BLOCK_HEIGHT;
1058                                 block_width = IMGU_OSYS_BLOCK_WIDTH;
1059                         }
1060                         block_width_vecs =
1061                                         block_width / IMGU_VMEM1_ELEMS_PER_VEC;
1062                         /*
1063                          * The input/output line stride depends on the
1064                          * block size.
1065                          */
1066                         input_buf_y_line_stride = block_width_vecs;
1067                         input_buf_uv_line_stride = block_width_vecs / 2;
1068                         output_buf_y_line_stride = block_width_vecs;
1069                         output_buf_uv_line_stride = block_width_vecs / 2;
1070                         output_buf_nr_y_lines = block_height;
1071                         if (frame_params[pin].format ==
1072                             IMGU_ABI_OSYS_FORMAT_NV12 ||
1073                             frame_params[pin].format ==
1074                             IMGU_ABI_OSYS_FORMAT_NV21)
1075                                 output_buf_uv_line_stride =
1076                                         output_buf_y_line_stride;
1077 
1078                         /*
1079                          * Tiled outputs use a different output buffer
1080                          * configuration. The input (= scaler output) block
1081                          * width translates to a tile height, and the block
1082                          * height to the tile width. The default block size of
1083                          * 128x32 maps exactly onto a 4kB tile (512x8) for Y.
1084                          * For UV, the tile width is always half.
1085                          */
1086                         if (frame_params[pin].tiling) {
1087                                 output_buf_nr_y_lines = 8;
1088                                 output_buf_y_line_stride = 512 /
1089                                         IMGU_VMEM1_ELEMS_PER_VEC;
1090                                 output_buf_uv_line_stride = 256 /
1091                                         IMGU_VMEM1_ELEMS_PER_VEC;
1092                         }
1093 
1094                         /*
1095                          * Store the output buffer line stride. Will be
1096                          * used to compute buffer offsets in boundary
1097                          * conditions when output blocks are partially
1098                          * outside the image.
1099                          */
1100                         osys->stripe[s].buf_stride[pin] =
1101                                 output_buf_y_line_stride *
1102                                 IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS;
1103                         if (frame_params[pin].scaled) {
1104                                 /*
1105                                  * The input buffs are the intermediate
1106                                  * buffers (scalers' output)
1107                                  */
1108                                 input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
1109                                 input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
1110                                                         IMGU_VMEM1_U_OFFSET;
1111                                 input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
1112                                                         IMGU_VMEM1_V_OFFSET;
1113                         } else {
1114                                 /*
1115                                  * The input bufferss are the buffers
1116                                  * filled by the SP
1117                                  */
1118                                 input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
1119                                 input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
1120                                                         IMGU_VMEM1_U_OFFSET;
1121                                 input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
1122                                                         IMGU_VMEM1_V_OFFSET;
1123                         }
1124 
1125                         /*
1126                          * The formatter input width must be rounded to
1127                          * the block width. Otherwise the formatter will
1128                          * not recognize the end of the line, resulting
1129                          * in incorrect tiling (system may hang!) and
1130                          * possibly other problems.
1131                          */
1132                         input_width_s =
1133                                 roundup(stripe_params[s].output_width[pin],
1134                                         block_width);
1135                         input_width_vecs = input_width_s /
1136                                         IMGU_VMEM1_ELEMS_PER_VEC;
1137                         out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
1138                         /*
1139                          * Process-output tokens must be sent to the SP.
1140                          * When scaling, the release-input tokens can be
1141                          * sent directly to the scaler, otherwise the
1142                          * formatter should send them to the SP.
1143                          */
1144                         if (frame_params[pin].scaled)
1145                                 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER;
1146                         else
1147                                 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
1148 
1149                         /* Formatter */
1150                         param = &osys->formatter[s][pin].param;
1151 
1152                         param->format = frame_params[pin].format;
1153                         param->flip = frame_params[pin].flip;
1154                         param->mirror = frame_params[pin].mirror;
1155                         param->tiling = frame_params[pin].tiling;
1156                         param->reduce_range = frame_params[pin].reduce_range;
1157                         param->alpha_blending = 0;
1158                         param->release_inp_addr = in_fifo_addr;
1159                         param->release_inp_en = 1;
1160                         param->process_out_buf_addr = out_fifo_addr;
1161                         param->image_width_vecs = input_width_vecs;
1162                         param->image_height_lines =
1163                                 stripe_params[s].output_height[pin];
1164                         param->inp_buff_y_st_addr = input_buf_y_st_addr;
1165                         param->inp_buff_y_line_stride = input_buf_y_line_stride;
1166                         param->inp_buff_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
1167                         param->int_buff_u_st_addr = input_buf_u_st_addr;
1168                         param->int_buff_v_st_addr = input_buf_v_st_addr;
1169                         param->inp_buff_uv_line_stride =
1170                                 input_buf_uv_line_stride;
1171                         param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
1172                         param->out_buff_level = 0;
1173                         param->out_buff_nr_y_lines = output_buf_nr_y_lines;
1174                         param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET;
1175                         param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET;
1176                         param->out_buff_y_line_stride =
1177                                 output_buf_y_line_stride;
1178                         param->out_buff_uv_line_stride =
1179                                 output_buf_uv_line_stride;
1180                         param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR;
1181                         param->hist_buff_line_stride =
1182                                 IMGU_VMEM1_HST_BUF_STRIDE;
1183                         param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES;
1184                 }
1185         }
1186 
1187         block_stripes[0].offset = 0;
1188         if (stripes <= 1) {
1189                 block_stripes[0].width = stripe_params[0].input_width;
1190                 block_stripes[0].height = stripe_params[0].input_height;
1191         } else {
1192                 struct imgu_fw_info *bi =
1193                         &css->fwp->binary_header[css_pipe->bindex];
1194                 unsigned int sp_block_width =
1195                                 bi->info.isp.sp.block.block_width *
1196                                 IPU3_UAPI_ISP_VEC_ELEMS;
1197 
1198                 block_stripes[0].width = roundup(stripe_params[0].input_width,
1199                                                  sp_block_width);
1200                 block_stripes[1].offset =
1201                         rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
1202                                   stripe_params[1].input_width, sp_block_width);
1203                 block_stripes[1].width =
1204                         roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
1205                                 block_stripes[1].offset, sp_block_width);
1206                 block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
1207                 block_stripes[1].height = block_stripes[0].height;
1208         }
1209 
1210         return 0;
1211 }
1212 
1213 /*********************** Mostly 3A operations ******************************/
1214 
1215 /*
1216  * This function creates a "TO-DO list" (operations) for the sp code.
1217  *
1218  * There are 2 types of operations:
1219  * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to
1220  *    accelerator space (NOTE that this space is limited) associated data:
1221  *    DDR address + accelerator's config set index(acc's address).
1222  *
1223  * 2. Issue "Process Lines Command" to shd accelerator
1224  *    associated data: #lines + which config set to use (actually, accelerator
1225  *    will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction
1226  *    of not touching config sets x & (x+1)%num_of_sets when process_lines(x)
1227  *    is active).
1228  *
1229  * Basically there are 2 types of operations "chunks":
1230  * 1. "initial chunk": Initially, we do as much transfers as we can (and need)
1231  *    [0 - max sets(3) ] followed by 1 or 2 "process lines" operations.
1232  *
1233  * 2. "regular chunk" - 1 transfer followed by 1 process line operation.
1234  *    (in some cases we might need additional transfer ate the last chunk).
1235  *
1236  * for some case:
1237  * --> init
1238  *      tr (0)
1239  *      tr (1)
1240  *      tr (2)
1241  *      pl (0)
1242  *      pl (1)
1243  * --> ack (0)
1244  *      tr (3)
1245  *      pl (2)
1246  * --> ack (1)
1247  *      pl (3)
1248  * --> ack (2)
1249  *      do nothing
1250  * --> ack (3)
1251  *      do nothing
1252  */
1253 
1254 static int
1255 imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops,
1256                       const struct ipu3_uapi_shd_grid_config *grid,
1257                       unsigned int image_height)
1258 {
1259         unsigned int block_height = 1 << grid->block_height_log2;
1260         unsigned int grid_height_per_slice = grid->grid_height_per_slice;
1261         unsigned int set_height = grid_height_per_slice * block_height;
1262 
1263         /* We currently support only abs(y_start) > grid_height_per_slice */
1264         unsigned int positive_y_start = (unsigned int)-grid->y_start;
1265         unsigned int first_process_lines =
1266                                 set_height - (positive_y_start % set_height);
1267         unsigned int last_set_height;
1268         unsigned int num_of_sets;
1269 
1270         struct imgu_abi_acc_operation *p_op;
1271         struct imgu_abi_acc_process_lines_cmd_data *p_pl;
1272         struct imgu_abi_shd_transfer_luts_set_data *p_tr;
1273 
1274         unsigned int op_idx, pl_idx, tr_idx;
1275         unsigned char tr_set_num, pl_cfg_set;
1276 
1277         /*
1278          * When the number of lines for the last process lines command
1279          * is equal to a set height, we need another line of grid cell -
1280          * additional transfer is required.
1281          */
1282         unsigned char last_tr = 0;
1283 
1284         /* Add "process lines" command to the list of operations */
1285         bool add_pl;
1286         /* Add DMA xfer (config set) command to the list of ops */
1287         bool add_tr;
1288 
1289         /*
1290          * Available partial grid (the part that fits into #IMGU_SHD_SETS sets)
1291          * doesn't cover whole frame - need to process in chunks
1292          */
1293         if (image_height > first_process_lines) {
1294                 last_set_height =
1295                         (image_height - first_process_lines) % set_height;
1296                 num_of_sets = last_set_height > 0 ?
1297                         (image_height - first_process_lines) / set_height + 2 :
1298                         (image_height - first_process_lines) / set_height + 1;
1299                 last_tr = (set_height - last_set_height <= block_height ||
1300                            last_set_height == 0) ? 1 : 0;
1301         } else { /* partial grid covers whole frame */
1302                 last_set_height = 0;
1303                 num_of_sets = 1;
1304                 first_process_lines = image_height;
1305                 last_tr = set_height - image_height <= block_height ? 1 : 0;
1306         }
1307 
1308         /* Init operations lists and counters */
1309         p_op = ops->operation_list;
1310         op_idx = 0;
1311         p_pl = ops->process_lines_data;
1312         pl_idx = 0;
1313         p_tr = ops->transfer_data;
1314         tr_idx = 0;
1315 
1316         memset(ops, 0, sizeof(*ops));
1317 
1318         /* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */
1319         tr_set_num = 0;
1320         pl_cfg_set = 0;
1321 
1322         /*
1323          * Always start with a transfer - process lines command must be
1324          * initiated only after appropriate config sets are in place
1325          * (2 configuration sets per process line command, except for last one).
1326          */
1327         add_pl = false;
1328         add_tr = true;
1329 
1330         while (add_pl || add_tr) {
1331                 /* Transfer ops */
1332                 if (add_tr) {
1333                         if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
1334                             tr_idx >= IMGU_ABI_SHD_MAX_TRANSFERS)
1335                                 return -EINVAL;
1336                         p_op[op_idx].op_type =
1337                                 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
1338                         p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE;
1339                         op_idx++;
1340                         p_tr[tr_idx].set_number = tr_set_num;
1341                         tr_idx++;
1342                         tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS;
1343                 }
1344 
1345                 /* Process-lines ops */
1346                 if (add_pl) {
1347                         if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
1348                             pl_idx >= IMGU_ABI_SHD_MAX_PROCESS_LINES)
1349                                 return -EINVAL;
1350                         p_op[op_idx].op_type =
1351                                 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1352 
1353                         /*
1354                          * In case we have 2 process lines commands -
1355                          * don't stop after the first one
1356                          */
1357                         if (pl_idx == 0 && num_of_sets != 1)
1358                                 p_op[op_idx].op_indicator =
1359                                         IMGU_ABI_ACC_OP_IDLE;
1360                         /*
1361                          * Initiate last process lines command -
1362                          * end of operation list.
1363                          */
1364                         else if (pl_idx == num_of_sets - 1)
1365                                 p_op[op_idx].op_indicator =
1366                                         IMGU_ABI_ACC_OP_END_OF_OPS;
1367                         /*
1368                          * Intermediate process line command - end of operation
1369                          * "chunk" (meaning few "transfers" followed by few
1370                          * "process lines" commands).
1371                          */
1372                         else
1373                                 p_op[op_idx].op_indicator =
1374                                         IMGU_ABI_ACC_OP_END_OF_ACK;
1375 
1376                         op_idx++;
1377 
1378                         /* first process line operation */
1379                         if (pl_idx == 0)
1380                                 p_pl[pl_idx].lines = first_process_lines;
1381                         /* Last process line operation */
1382                         else if (pl_idx == num_of_sets - 1 &&
1383                                  last_set_height > 0)
1384                                 p_pl[pl_idx].lines = last_set_height;
1385                         else    /* "regular" process lines operation */
1386                                 p_pl[pl_idx].lines = set_height;
1387 
1388                         p_pl[pl_idx].cfg_set = pl_cfg_set;
1389                         pl_idx++;
1390                         pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS;
1391                 }
1392 
1393                 /*
1394                  * Initially, we always transfer
1395                  * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the
1396                  * corresponding process lines commands.
1397                  */
1398                 if (tr_idx == IMGU_SHD_SETS ||
1399                     tr_idx == num_of_sets + last_tr) {
1400                         add_tr = false;
1401                         add_pl = true;
1402                 }
1403 
1404                 /*
1405                  * We have finished the "initial" operations chunk -
1406                  * be ready to get more chunks.
1407                  */
1408                 if (pl_idx == 2) {
1409                         add_tr = true;
1410                         add_pl = true;
1411                 }
1412 
1413                 /* Stop conditions for each operation type */
1414                 if (tr_idx == num_of_sets + last_tr)
1415                         add_tr = false;
1416                 if (pl_idx == num_of_sets)
1417                         add_pl = false;
1418         }
1419 
1420         return 0;
1421 }
1422 
1423 /*
1424  * The follow handshake procotol is the same for AF, AWB and AWB FR.
1425  *
1426  * for n sets of meta-data, the flow is:
1427  * --> init
1428  *  process-lines  (0)
1429  *  process-lines  (1)   eoc
1430  *  --> ack (0)
1431  *  read-meta-data (0)
1432  *  process-lines  (2)   eoc
1433  *  --> ack (1)
1434  *  read-meta-data (1)
1435  *  process-lines  (3)   eoc
1436  *  ...
1437  *
1438  *  --> ack (n-3)
1439  *  read-meta-data (n-3)
1440  *  process-lines  (n-1) eoc
1441  *  --> ack (n-2)
1442  *  read-meta-data (n-2) eoc
1443  *  --> ack (n-1)
1444  *  read-meta-data (n-1) eof
1445  *
1446  * for 2 sets we get:
1447  * --> init
1448  * pl (0)
1449  * pl (1) eoc
1450  * --> ack (0)
1451  * pl (2) - rest of image, if applicable)
1452  * rmd (0) eoc
1453  * --> ack (1)
1454  * rmd (1) eof
1455  * --> (ack (2))
1456  * do nothing
1457  *
1458  * for only one set:
1459  *
1460  * --> init
1461  * pl(0)   eoc
1462  * --> ack (0)
1463  * rmd (0) eof
1464  *
1465  * grid smaller than image case
1466  * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
1467  * start at (0,0)
1468  * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
1469  * => 1st process lines = 80
1470  * we're left with 128-80=48 lines (6 blocks vertical)
1471  * => 2nd process lines = 48
1472  * last process lines to cover the image - image_height - 128
1473  *
1474  * --> init
1475  * pl (0) first
1476  * pl (1) last-in-grid
1477  * --> ack (0)
1478  * rmd (0)
1479  * pl (2) after-grid
1480  * --> ack (1)
1481  * rmd (1) eof
1482  * --> ack (2)
1483  * do nothing
1484  */
1485 struct process_lines {
1486         unsigned int image_height;
1487         unsigned short grid_height;
1488         unsigned short block_height;
1489         unsigned short y_start;
1490         unsigned char grid_height_per_slice;
1491 
1492         unsigned short max_op; /* max operation */
1493         unsigned short max_tr; /* max transaction */
1494         unsigned char acc_enable;
1495 };
1496 
1497 /* Helper to config intra_frame_operations_data. */
1498 static int
1499 imgu_css_acc_process_lines(const struct process_lines *pl,
1500                            struct imgu_abi_acc_operation *p_op,
1501                            struct imgu_abi_acc_process_lines_cmd_data *p_pl,
1502                            struct imgu_abi_acc_transfer_op_data *p_tr)
1503 {
1504         unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0;
1505         unsigned char tr_set_num = 0, pl_cfg_set = 0;
1506         const unsigned short grid_last_line =
1507                         pl->y_start + pl->grid_height * pl->block_height;
1508         const unsigned short process_lines =
1509                         pl->grid_height_per_slice * pl->block_height;
1510 
1511         unsigned int process_lines_after_grid;
1512         unsigned short first_process_lines;
1513         unsigned short last_process_lines_in_grid;
1514 
1515         unsigned short num_of_process_lines;
1516         unsigned short num_of_sets;
1517 
1518         if (pl->grid_height_per_slice == 0)
1519                 return -EINVAL;
1520 
1521         if (pl->acc_enable && grid_last_line > pl->image_height)
1522                 return -EINVAL;
1523 
1524         num_of_sets = pl->grid_height / pl->grid_height_per_slice;
1525         if (num_of_sets * pl->grid_height_per_slice < pl->grid_height)
1526                 num_of_sets++;
1527 
1528         /* Account for two line delay inside the FF */
1529         if (pl->max_op == IMGU_ABI_AF_MAX_OPERATIONS) {
1530                 first_process_lines = process_lines + pl->y_start + 2;
1531                 last_process_lines_in_grid =
1532                         (grid_last_line - first_process_lines) -
1533                         ((num_of_sets - 2) * process_lines) + 4;
1534                 process_lines_after_grid =
1535                         pl->image_height - grid_last_line - 4;
1536         } else {
1537                 first_process_lines = process_lines + pl->y_start;
1538                 last_process_lines_in_grid =
1539                         (grid_last_line - first_process_lines) -
1540                         ((num_of_sets - 2) * process_lines);
1541                 process_lines_after_grid = pl->image_height - grid_last_line;
1542         }
1543 
1544         num_of_process_lines = num_of_sets;
1545         if (process_lines_after_grid > 0)
1546                 num_of_process_lines++;
1547 
1548         while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) {
1549                 /* Read meta-data */
1550                 if (pl_idx >= 2 || (pl_idx == 1 && num_of_sets == 1)) {
1551                         if (op_idx >= pl->max_op || tr_idx >= pl->max_tr)
1552                                 return -EINVAL;
1553 
1554                         p_op[op_idx].op_type =
1555                                 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
1556 
1557                         if (tr_idx == num_of_sets - 1)
1558                                 /* The last operation is always a tr */
1559                                 p_op[op_idx].op_indicator =
1560                                         IMGU_ABI_ACC_OP_END_OF_OPS;
1561                         else if (tr_idx == num_of_sets - 2)
1562                                 if (process_lines_after_grid == 0)
1563                                         /*
1564                                          * No additional pl op left -
1565                                          * this op is left as lats of cycle
1566                                          */
1567                                         p_op[op_idx].op_indicator =
1568                                                 IMGU_ABI_ACC_OP_END_OF_ACK;
1569                                 else
1570                                         /*
1571                                          * We still have to process-lines after
1572                                          * the grid so have one more pl op
1573                                          */
1574                                         p_op[op_idx].op_indicator =
1575                                                 IMGU_ABI_ACC_OP_IDLE;
1576                         else
1577                                 /* Default - usually there's a pl after a tr */
1578                                 p_op[op_idx].op_indicator =
1579                                         IMGU_ABI_ACC_OP_IDLE;
1580 
1581                         op_idx++;
1582                         if (p_tr) {
1583                                 p_tr[tr_idx].set_number = tr_set_num;
1584                                 tr_set_num = 1 - tr_set_num;
1585                         }
1586                         tr_idx++;
1587                 }
1588 
1589                 /* process_lines */
1590                 if (pl_idx < num_of_process_lines) {
1591                         if (op_idx >= pl->max_op || pl_idx >= pl->max_tr)
1592                                 return -EINVAL;
1593 
1594                         p_op[op_idx].op_type =
1595                                 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1596                         if (pl_idx == 0)
1597                                 if (num_of_process_lines == 1)
1598                                         /* Only one pl op */
1599                                         p_op[op_idx].op_indicator =
1600                                                 IMGU_ABI_ACC_OP_END_OF_ACK;
1601                                 else
1602                                         /* On init - do two pl ops */
1603                                         p_op[op_idx].op_indicator =
1604                                                 IMGU_ABI_ACC_OP_IDLE;
1605                         else
1606                                 /* Usually pl is the end of the ack cycle */
1607                                 p_op[op_idx].op_indicator =
1608                                         IMGU_ABI_ACC_OP_END_OF_ACK;
1609 
1610                         op_idx++;
1611 
1612                         if (pl_idx == 0)
1613                                 /* First process line */
1614                                 p_pl[pl_idx].lines = first_process_lines;
1615                         else if (pl_idx == num_of_sets - 1)
1616                                 /* Last in grid */
1617                                 p_pl[pl_idx].lines = last_process_lines_in_grid;
1618                         else if (pl_idx == num_of_process_lines - 1)
1619                                 /* After the grid */
1620                                 p_pl[pl_idx].lines = process_lines_after_grid;
1621                         else
1622                                 /* Inside the grid */
1623                                 p_pl[pl_idx].lines = process_lines;
1624 
1625                         if (p_tr) {
1626                                 p_pl[pl_idx].cfg_set = pl_cfg_set;
1627                                 pl_cfg_set = 1 - pl_cfg_set;
1628                         }
1629                         pl_idx++;
1630                 }
1631         }
1632 
1633         return 0;
1634 }
1635 
1636 static int imgu_css_af_ops_calc(struct imgu_css *css, unsigned int pipe,
1637                                 struct imgu_abi_af_config *af_config)
1638 {
1639         struct imgu_abi_af_intra_frame_operations_data *to =
1640                 &af_config->operations_data;
1641         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1642         struct imgu_fw_info *bi =
1643                 &css->fwp->binary_header[css_pipe->bindex];
1644 
1645         struct process_lines pl = {
1646                 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1647                 .grid_height = af_config->config.grid_cfg.height,
1648                 .block_height =
1649                         1 << af_config->config.grid_cfg.block_height_log2,
1650                 .y_start = af_config->config.grid_cfg.y_start &
1651                         IPU3_UAPI_GRID_START_MASK,
1652                 .grid_height_per_slice =
1653                         af_config->stripes[0].grid_cfg.height_per_slice,
1654                 .max_op = IMGU_ABI_AF_MAX_OPERATIONS,
1655                 .max_tr = IMGU_ABI_AF_MAX_TRANSFERS,
1656                 .acc_enable = bi->info.isp.sp.enable.af,
1657         };
1658 
1659         return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1660                                           NULL);
1661 }
1662 
1663 static int
1664 imgu_css_awb_fr_ops_calc(struct imgu_css *css, unsigned int pipe,
1665                          struct imgu_abi_awb_fr_config *awb_fr_config)
1666 {
1667         struct imgu_abi_awb_fr_intra_frame_operations_data *to =
1668                 &awb_fr_config->operations_data;
1669         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1670         struct imgu_fw_info *bi =
1671                 &css->fwp->binary_header[css_pipe->bindex];
1672         struct process_lines pl = {
1673                 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1674                 .grid_height = awb_fr_config->config.grid_cfg.height,
1675                 .block_height =
1676                         1 << awb_fr_config->config.grid_cfg.block_height_log2,
1677                 .y_start = awb_fr_config->config.grid_cfg.y_start &
1678                         IPU3_UAPI_GRID_START_MASK,
1679                 .grid_height_per_slice =
1680                         awb_fr_config->stripes[0].grid_cfg.height_per_slice,
1681                 .max_op = IMGU_ABI_AWB_FR_MAX_OPERATIONS,
1682                 .max_tr = IMGU_ABI_AWB_FR_MAX_PROCESS_LINES,
1683                 .acc_enable = bi->info.isp.sp.enable.awb_fr_acc,
1684         };
1685 
1686         return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1687                                           NULL);
1688 }
1689 
1690 static int imgu_css_awb_ops_calc(struct imgu_css *css, unsigned int pipe,
1691                                  struct imgu_abi_awb_config *awb_config)
1692 {
1693         struct imgu_abi_awb_intra_frame_operations_data *to =
1694                 &awb_config->operations_data;
1695         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1696         struct imgu_fw_info *bi =
1697                 &css->fwp->binary_header[css_pipe->bindex];
1698 
1699         struct process_lines pl = {
1700                 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1701                 .grid_height = awb_config->config.grid.height,
1702                 .block_height =
1703                         1 << awb_config->config.grid.block_height_log2,
1704                 .y_start = awb_config->config.grid.y_start,
1705                 .grid_height_per_slice =
1706                         awb_config->stripes[0].grid.height_per_slice,
1707                 .max_op = IMGU_ABI_AWB_MAX_OPERATIONS,
1708                 .max_tr = IMGU_ABI_AWB_MAX_TRANSFERS,
1709                 .acc_enable = bi->info.isp.sp.enable.awb_acc,
1710         };
1711 
1712         return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1713                                           to->transfer_data);
1714 }
1715 
1716 static u16 imgu_css_grid_end(u16 start, u8 width, u8 block_width_log2)
1717 {
1718         return (start & IPU3_UAPI_GRID_START_MASK) +
1719                 (width << block_width_log2) - 1;
1720 }
1721 
1722 static void imgu_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg)
1723 {
1724         grid_cfg->x_end = imgu_css_grid_end(grid_cfg->x_start, grid_cfg->width,
1725                                             grid_cfg->block_width_log2);
1726         grid_cfg->y_end = imgu_css_grid_end(grid_cfg->y_start, grid_cfg->height,
1727                                             grid_cfg->block_height_log2);
1728 }
1729 
1730 /****************** config computation *****************************/
1731 
1732 static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe,
1733                                    struct imgu_abi_acc_param *acc)
1734 {
1735         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1736         const struct imgu_fw_info *bi =
1737                 &css->fwp->binary_header[css_pipe->bindex];
1738         struct imgu_css_scaler_info scaler_luma, scaler_chroma;
1739         const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
1740         const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2;
1741         unsigned int bds_ds, i;
1742 
1743         memset(acc, 0, sizeof(*acc));
1744 
1745         /* acc_param: osys_config */
1746 
1747         if (imgu_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma,
1748                                &scaler_chroma, acc->stripe.block_stripes))
1749                 return -EINVAL;
1750 
1751         /* acc_param: stripe data */
1752 
1753         /*
1754          * For the striped case the approach is as follows:
1755          * 1. down-scaled stripes are calculated - with 128 overlap
1756          *    (this is the main limiter therefore it's first)
1757          * 2. input stripes are derived by up-scaling the down-scaled stripes
1758          *    (there are no alignment requirements on input stripes)
1759          * 3. output stripes are derived from down-scaled stripes too
1760          */
1761 
1762         acc->stripe.num_of_stripes = stripes;
1763         acc->stripe.input_frame.width =
1764                 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
1765         acc->stripe.input_frame.height =
1766                 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
1767         acc->stripe.input_frame.bayer_order =
1768                 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
1769 
1770         for (i = 0; i < stripes; i++)
1771                 acc->stripe.bds_out_stripes[i].height =
1772                                         css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1773         acc->stripe.bds_out_stripes[0].offset = 0;
1774         if (stripes <= 1) {
1775                 acc->stripe.bds_out_stripes[0].width =
1776                         ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
1777         } else {
1778                 /* Image processing is divided into two stripes */
1779                 acc->stripe.bds_out_stripes[0].width =
1780                         acc->stripe.bds_out_stripes[1].width =
1781                         (css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f;
1782                 /*
1783                  * Sum of width of the two stripes should not be smaller
1784                  * than output width and must be even times of overlapping
1785                  * unit f.
1786                  */
1787                 if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) !=
1788                     !!(css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1)))
1789                         acc->stripe.bds_out_stripes[0].width += f;
1790                 if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) &&
1791                     (css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) {
1792                         acc->stripe.bds_out_stripes[0].width += f;
1793                         acc->stripe.bds_out_stripes[1].width += f;
1794                 }
1795                 /* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
1796                 acc->stripe.bds_out_stripes[1].offset =
1797                         acc->stripe.bds_out_stripes[0].width - 2 * f;
1798         }
1799 
1800         acc->stripe.effective_stripes[0].height =
1801                                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
1802         acc->stripe.effective_stripes[0].offset = 0;
1803         acc->stripe.bds_out_stripes_no_overlap[0].height =
1804                                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1805         acc->stripe.bds_out_stripes_no_overlap[0].offset = 0;
1806         acc->stripe.output_stripes[0].height =
1807                                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1808         acc->stripe.output_stripes[0].offset = 0;
1809         if (stripes <= 1) {
1810                 acc->stripe.down_scaled_stripes[0].width =
1811                                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1812                 acc->stripe.down_scaled_stripes[0].height =
1813                                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1814                 acc->stripe.down_scaled_stripes[0].offset = 0;
1815 
1816                 acc->stripe.effective_stripes[0].width =
1817                                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
1818                 acc->stripe.bds_out_stripes_no_overlap[0].width =
1819                         ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
1820 
1821                 acc->stripe.output_stripes[0].width =
1822                         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
1823         } else { /* Two stripes */
1824                 bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width *
1825                                 IMGU_BDS_GRANULARITY /
1826                                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1827 
1828                 acc->stripe.down_scaled_stripes[0] =
1829                         acc->stripe.bds_out_stripes[0];
1830                 acc->stripe.down_scaled_stripes[1] =
1831                         acc->stripe.bds_out_stripes[1];
1832                 if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f))
1833                         acc->stripe.down_scaled_stripes[1].width +=
1834                                 (css_pipe->rect[IPU3_CSS_RECT_BDS].width
1835                                 & (f - 1)) - f;
1836 
1837                 acc->stripe.effective_stripes[0].width = bds_ds *
1838                         acc->stripe.down_scaled_stripes[0].width /
1839                         IMGU_BDS_GRANULARITY;
1840                 acc->stripe.effective_stripes[1].width = bds_ds *
1841                         acc->stripe.down_scaled_stripes[1].width /
1842                         IMGU_BDS_GRANULARITY;
1843                 acc->stripe.effective_stripes[1].height =
1844                         css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
1845                 acc->stripe.effective_stripes[1].offset = bds_ds *
1846                         acc->stripe.down_scaled_stripes[1].offset /
1847                         IMGU_BDS_GRANULARITY;
1848 
1849                 acc->stripe.bds_out_stripes_no_overlap[0].width =
1850                 acc->stripe.bds_out_stripes_no_overlap[1].offset =
1851                         ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2;
1852                 acc->stripe.bds_out_stripes_no_overlap[1].width =
1853                         DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)
1854                         / 2 * f;
1855                 acc->stripe.bds_out_stripes_no_overlap[1].height =
1856                         css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1857 
1858                 acc->stripe.output_stripes[0].width =
1859                         acc->stripe.down_scaled_stripes[0].width - f;
1860                 acc->stripe.output_stripes[1].width =
1861                         acc->stripe.down_scaled_stripes[1].width - f;
1862                 acc->stripe.output_stripes[1].height =
1863                         css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1864                 acc->stripe.output_stripes[1].offset =
1865                         acc->stripe.output_stripes[0].width;
1866         }
1867 
1868         acc->stripe.output_system_in_frame_width =
1869                 css_pipe->rect[IPU3_CSS_RECT_GDC].width;
1870         acc->stripe.output_system_in_frame_height =
1871                 css_pipe->rect[IPU3_CSS_RECT_GDC].height;
1872 
1873         acc->stripe.effective_frame_width =
1874                                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
1875         acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1876         acc->stripe.out_frame_width =
1877                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
1878         acc->stripe.out_frame_height =
1879                 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1880         acc->stripe.gdc_in_buffer_width =
1881                 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
1882                 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
1883         acc->stripe.gdc_in_buffer_height =
1884                 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
1885         acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X;
1886         acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y;
1887         acc->stripe.display_frame_width =
1888                 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
1889         acc->stripe.display_frame_height =
1890                 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
1891         acc->stripe.bds_aligned_frame_width =
1892                 roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
1893                         2 * IPU3_UAPI_ISP_VEC_ELEMS);
1894 
1895         if (stripes > 1)
1896                 acc->stripe.half_overlap_vectors =
1897                         IMGU_STRIPE_FIXED_HALF_OVERLAP;
1898         else
1899                 acc->stripe.half_overlap_vectors = 0;
1900 
1901         return 0;
1902 }
1903 
1904 static void imgu_css_cfg_acc_dvs(struct imgu_css *css,
1905                                  struct imgu_abi_acc_param *acc,
1906                                  unsigned int pipe)
1907 {
1908         unsigned int i;
1909         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1910 
1911         /* Disable DVS statistics */
1912         acc->dvs_stat.operations_data.process_lines_data[0].lines =
1913                                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1914         acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0;
1915         acc->dvs_stat.operations_data.ops[0].op_type =
1916                 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1917         acc->dvs_stat.operations_data.ops[0].op_indicator =
1918                 IMGU_ABI_ACC_OP_NO_OPS;
1919         for (i = 0; i < IMGU_ABI_DVS_STAT_LEVELS; i++)
1920                 acc->dvs_stat.cfg.grd_config[i].enable = 0;
1921 }
1922 
1923 static void acc_bds_per_stripe_data(struct imgu_css *css,
1924                                     struct imgu_abi_acc_param *acc,
1925                                     const int i, unsigned int pipe)
1926 {
1927         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1928 
1929         acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0;
1930         acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0;
1931         acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0;
1932         acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 =
1933                 acc->bds.hor.hor_ctrl0;
1934         acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width =
1935                 acc->stripe.down_scaled_stripes[i].width;
1936         acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width =
1937                 acc->stripe.down_scaled_stripes[i].width;
1938         acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height =
1939                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1940 }
1941 
1942 /*
1943  * Configure `acc' parameters. `acc_old' contains the old values (or is NULL)
1944  * and `acc_user' contains new prospective values. `use' contains flags
1945  * telling which fields to take from the old values (or generate if it is NULL)
1946  * and which to take from the new user values.
1947  */
1948 int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe,
1949                      struct ipu3_uapi_flags *use,
1950                      struct imgu_abi_acc_param *acc,
1951                      struct imgu_abi_acc_param *acc_old,
1952                      struct ipu3_uapi_acc_param *acc_user)
1953 {
1954         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1955         const struct imgu_fw_info *bi =
1956                 &css->fwp->binary_header[css_pipe->bindex];
1957         const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
1958         const unsigned int tnr_frame_width =
1959                 acc->stripe.bds_aligned_frame_width;
1960         const unsigned int min_overlap = 10;
1961         const struct v4l2_pix_format_mplane *pixm =
1962                 &css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
1963         const struct imgu_css_bds_config *cfg_bds;
1964         struct imgu_abi_input_feeder_data *feeder_data;
1965 
1966         unsigned int bds_ds, ofs_x, ofs_y, i, width, height;
1967         u8 b_w_log2; /* Block width log2 */
1968 
1969         /* Update stripe using chroma and luma */
1970 
1971         if (imgu_css_cfg_acc_stripe(css, pipe, acc))
1972                 return -EINVAL;
1973 
1974         /* acc_param: input_feeder_config */
1975 
1976         ofs_x = ((pixm->width -
1977                   css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
1978         ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1979                 IMGU_ABI_BAYER_ORDER_RGGB ||
1980                 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1981                 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
1982         ofs_y = ((pixm->height -
1983                   css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
1984         ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1985                 IMGU_ABI_BAYER_ORDER_BGGR ||
1986                 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1987                 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
1988         acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline;
1989         acc->input_feeder.data.start_row_address =
1990                 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
1991                 ofs_y * acc->input_feeder.data.row_stride;
1992         acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
1993 
1994         acc->input_feeder.data_per_stripe.input_feeder_data[0].data =
1995                 acc->input_feeder.data;
1996 
1997         ofs_x += acc->stripe.effective_stripes[1].offset;
1998 
1999         feeder_data =
2000                 &acc->input_feeder.data_per_stripe.input_feeder_data[1].data;
2001         feeder_data->row_stride = acc->input_feeder.data.row_stride;
2002         feeder_data->start_row_address =
2003                 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
2004                 ofs_y * acc->input_feeder.data.row_stride;
2005         feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
2006 
2007         /* acc_param: bnr_static_config */
2008 
2009         /*
2010          * Originate from user or be the original default values if user has
2011          * never set them before, when user gives a new set of parameters,
2012          * for each chunk in the parameter structure there is a flag use->xxx
2013          * whether to use the user-provided parameter or not. If not, the
2014          * parameter remains unchanged in the driver:
2015          * it's value is taken from acc_old.
2016          */
2017         if (use && use->acc_bnr) {
2018                 /* Take values from user */
2019                 acc->bnr = acc_user->bnr;
2020         } else if (acc_old) {
2021                 /* Use old value */
2022                 acc->bnr = acc_old->bnr;
2023         } else {
2024                 /* Calculate from scratch */
2025                 acc->bnr = imgu_css_bnr_defaults;
2026         }
2027 
2028         acc->bnr.column_size = tnr_frame_width;
2029 
2030         /* acc_param: bnr_static_config_green_disparity */
2031 
2032         if (use && use->acc_green_disparity) {
2033                 /* Take values from user */
2034                 acc->green_disparity = acc_user->green_disparity;
2035         } else if (acc_old) {
2036                 /* Use old value */
2037                 acc->green_disparity = acc_old->green_disparity;
2038         } else {
2039                 /* Calculate from scratch */
2040                 memset(&acc->green_disparity, 0, sizeof(acc->green_disparity));
2041         }
2042 
2043         /* acc_param: dm_config */
2044 
2045         if (use && use->acc_dm) {
2046                 /* Take values from user */
2047                 acc->dm = acc_user->dm;
2048         } else if (acc_old) {
2049                 /* Use old value */
2050                 acc->dm = acc_old->dm;
2051         } else {
2052                 /* Calculate from scratch */
2053                 acc->dm = imgu_css_dm_defaults;
2054         }
2055 
2056         acc->dm.frame_width = tnr_frame_width;
2057 
2058         /* acc_param: ccm_mat_config */
2059 
2060         if (use && use->acc_ccm) {
2061                 /* Take values from user */
2062                 acc->ccm = acc_user->ccm;
2063         } else if (acc_old) {
2064                 /* Use old value */
2065                 acc->ccm = acc_old->ccm;
2066         } else {
2067                 /* Calculate from scratch */
2068                 acc->ccm = imgu_css_ccm_defaults;
2069         }
2070 
2071         /* acc_param: gamma_config */
2072 
2073         if (use && use->acc_gamma) {
2074                 /* Take values from user */
2075                 acc->gamma = acc_user->gamma;
2076         } else if (acc_old) {
2077                 /* Use old value */
2078                 acc->gamma = acc_old->gamma;
2079         } else {
2080                 /* Calculate from scratch */
2081                 acc->gamma.gc_ctrl.enable = 1;
2082                 acc->gamma.gc_lut = imgu_css_gamma_lut;
2083         }
2084 
2085         /* acc_param: csc_mat_config */
2086 
2087         if (use && use->acc_csc) {
2088                 /* Take values from user */
2089                 acc->csc = acc_user->csc;
2090         } else if (acc_old) {
2091                 /* Use old value */
2092                 acc->csc = acc_old->csc;
2093         } else {
2094                 /* Calculate from scratch */
2095                 acc->csc = imgu_css_csc_defaults;
2096         }
2097 
2098         /* acc_param: cds_params */
2099 
2100         if (use && use->acc_cds) {
2101                 /* Take values from user */
2102                 acc->cds = acc_user->cds;
2103         } else if (acc_old) {
2104                 /* Use old value */
2105                 acc->cds = acc_old->cds;
2106         } else {
2107                 /* Calculate from scratch */
2108                 acc->cds = imgu_css_cds_defaults;
2109         }
2110 
2111         /* acc_param: shd_config */
2112 
2113         if (use && use->acc_shd) {
2114                 /* Take values from user */
2115                 acc->shd.shd = acc_user->shd.shd;
2116                 acc->shd.shd_lut = acc_user->shd.shd_lut;
2117         } else if (acc_old) {
2118                 /* Use old value */
2119                 acc->shd.shd = acc_old->shd.shd;
2120                 acc->shd.shd_lut = acc_old->shd.shd_lut;
2121         } else {
2122                 /* Calculate from scratch */
2123                 acc->shd.shd = imgu_css_shd_defaults;
2124                 memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut));
2125         }
2126 
2127         if (acc->shd.shd.grid.width <= 0)
2128                 return -EINVAL;
2129 
2130         acc->shd.shd.grid.grid_height_per_slice =
2131                 IMGU_ABI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width;
2132 
2133         if (acc->shd.shd.grid.grid_height_per_slice <= 0)
2134                 return -EINVAL;
2135 
2136         acc->shd.shd.general.init_set_vrt_offst_ul =
2137                                 (-acc->shd.shd.grid.y_start >>
2138                                  acc->shd.shd.grid.block_height_log2) %
2139                                 acc->shd.shd.grid.grid_height_per_slice;
2140 
2141         if (imgu_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid,
2142                                   css_pipe->rect[IPU3_CSS_RECT_BDS].height))
2143                 return -EINVAL;
2144 
2145         /* acc_param: dvs_stat_config */
2146         imgu_css_cfg_acc_dvs(css, acc, pipe);
2147 
2148         /* acc_param: yuvp1_iefd_config */
2149 
2150         if (use && use->acc_iefd) {
2151                 /* Take values from user */
2152                 acc->iefd = acc_user->iefd;
2153         } else if (acc_old) {
2154                 /* Use old value */
2155                 acc->iefd = acc_old->iefd;
2156         } else {
2157                 /* Calculate from scratch */
2158                 acc->iefd = imgu_css_iefd_defaults;
2159         }
2160 
2161         /* acc_param: yuvp1_yds_config yds_c0 */
2162 
2163         if (use && use->acc_yds_c0) {
2164                 /* Take values from user */
2165                 acc->yds_c0 = acc_user->yds_c0;
2166         } else if (acc_old) {
2167                 /* Use old value */
2168                 acc->yds_c0 = acc_old->yds_c0;
2169         } else {
2170                 /* Calculate from scratch */
2171                 acc->yds_c0 = imgu_css_yds_defaults;
2172         }
2173 
2174         /* acc_param: yuvp1_chnr_config chnr_c0 */
2175 
2176         if (use && use->acc_chnr_c0) {
2177                 /* Take values from user */
2178                 acc->chnr_c0 = acc_user->chnr_c0;
2179         } else if (acc_old) {
2180                 /* Use old value */
2181                 acc->chnr_c0 = acc_old->chnr_c0;
2182         } else {
2183                 /* Calculate from scratch */
2184                 acc->chnr_c0 = imgu_css_chnr_defaults;
2185         }
2186 
2187         /* acc_param: yuvp1_y_ee_nr_config */
2188 
2189         if (use && use->acc_y_ee_nr) {
2190                 /* Take values from user */
2191                 acc->y_ee_nr = acc_user->y_ee_nr;
2192         } else if (acc_old) {
2193                 /* Use old value */
2194                 acc->y_ee_nr = acc_old->y_ee_nr;
2195         } else {
2196                 /* Calculate from scratch */
2197                 acc->y_ee_nr = imgu_css_y_ee_nr_defaults;
2198         }
2199 
2200         /* acc_param: yuvp1_yds_config yds */
2201 
2202         if (use && use->acc_yds) {
2203                 /* Take values from user */
2204                 acc->yds = acc_user->yds;
2205         } else if (acc_old) {
2206                 /* Use old value */
2207                 acc->yds = acc_old->yds;
2208         } else {
2209                 /* Calculate from scratch */
2210                 acc->yds = imgu_css_yds_defaults;
2211         }
2212 
2213         /* acc_param: yuvp1_chnr_config chnr */
2214 
2215         if (use && use->acc_chnr) {
2216                 /* Take values from user */
2217                 acc->chnr = acc_user->chnr;
2218         } else if (acc_old) {
2219                 /* Use old value */
2220                 acc->chnr = acc_old->chnr;
2221         } else {
2222                 /* Calculate from scratch */
2223                 acc->chnr = imgu_css_chnr_defaults;
2224         }
2225 
2226         /* acc_param: yuvp2_y_tm_lut_static_config */
2227 
2228         for (i = 0; i < IMGU_ABI_YUVP2_YTM_LUT_ENTRIES; i++)
2229                 acc->ytm.entries[i] = i * 32;
2230         acc->ytm.enable = 0;    /* Always disabled on IPU3 */
2231 
2232         /* acc_param: yuvp1_yds_config yds2 */
2233 
2234         if (use && use->acc_yds2) {
2235                 /* Take values from user */
2236                 acc->yds2 = acc_user->yds2;
2237         } else if (acc_old) {
2238                 /* Use old value */
2239                 acc->yds2 = acc_old->yds2;
2240         } else {
2241                 /* Calculate from scratch */
2242                 acc->yds2 = imgu_css_yds_defaults;
2243         }
2244 
2245         /* acc_param: yuvp2_tcc_static_config */
2246 
2247         if (use && use->acc_tcc) {
2248                 /* Take values from user */
2249                 acc->tcc = acc_user->tcc;
2250         } else if (acc_old) {
2251                 /* Use old value */
2252                 acc->tcc = acc_old->tcc;
2253         } else {
2254                 /* Calculate from scratch */
2255                 memset(&acc->tcc, 0, sizeof(acc->tcc));
2256 
2257                 acc->tcc.gen_control.en = 1;
2258                 acc->tcc.gen_control.blend_shift = 3;
2259                 acc->tcc.gen_control.gain_according_to_y_only = 1;
2260                 acc->tcc.gen_control.gamma = 8;
2261                 acc->tcc.gen_control.delta = 0;
2262 
2263                 for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) {
2264                         acc->tcc.macc_table.entries[i].a = 1024;
2265                         acc->tcc.macc_table.entries[i].b = 0;
2266                         acc->tcc.macc_table.entries[i].c = 0;
2267                         acc->tcc.macc_table.entries[i].d = 1024;
2268                 }
2269 
2270                 acc->tcc.inv_y_lut.entries[6] = 1023;
2271                 for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++)
2272                         acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6);
2273 
2274                 acc->tcc.gain_pcwl = imgu_css_tcc_gain_pcwl_lut;
2275                 acc->tcc.r_sqr_lut = imgu_css_tcc_r_sqr_lut;
2276         }
2277 
2278         /* acc_param: dpc_config */
2279 
2280         if (use && use->acc_dpc)
2281                 return -EINVAL; /* Not supported yet */
2282 
2283         /* Just disable by default */
2284         memset(&acc->dpc, 0, sizeof(acc->dpc));
2285 
2286         /* acc_param: bds_config */
2287 
2288         bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height *
2289                   IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2290         if (bds_ds < IMGU_BDS_MIN_SF_INV ||
2291             bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(imgu_css_bds_configs))
2292                 return -EINVAL;
2293 
2294         cfg_bds = &imgu_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV];
2295         acc->bds.hor.hor_ctrl1.hor_crop_en = 0;
2296         acc->bds.hor.hor_ctrl1.hor_crop_start = 0;
2297         acc->bds.hor.hor_ctrl1.hor_crop_end = 0;
2298         acc->bds.hor.hor_ctrl0.sample_patrn_length =
2299                                 cfg_bds->sample_patrn_length;
2300         acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en;
2301         acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
2302         acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
2303         acc->bds.hor.hor_ctrl0.out_frame_width =
2304                                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
2305         acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr;
2306         acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr;
2307         acc->bds.hor.hor_ctrl2.input_frame_height =
2308                                 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
2309         acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
2310         acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
2311         acc->bds.ver.ver_ctrl0.sample_patrn_length =
2312                                 cfg_bds->sample_patrn_length;
2313         acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en;
2314         acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr;
2315         acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr;
2316         acc->bds.ver.ver_ctrl1.out_frame_width =
2317                                 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
2318         acc->bds.ver.ver_ctrl1.out_frame_height =
2319                                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2320         for (i = 0; i < stripes; i++)
2321                 acc_bds_per_stripe_data(css, acc, i, pipe);
2322 
2323         acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en;
2324 
2325         /* acc_param: anr_config */
2326 
2327         if (use && use->acc_anr) {
2328                 /* Take values from user */
2329                 acc->anr.transform = acc_user->anr.transform;
2330                 acc->anr.stitch.anr_stitch_en =
2331                         acc_user->anr.stitch.anr_stitch_en;
2332                 memcpy(acc->anr.stitch.pyramid, acc_user->anr.stitch.pyramid,
2333                        sizeof(acc->anr.stitch.pyramid));
2334         } else if (acc_old) {
2335                 /* Use old value */
2336                 acc->anr.transform = acc_old->anr.transform;
2337                 acc->anr.stitch.anr_stitch_en =
2338                         acc_old->anr.stitch.anr_stitch_en;
2339                 memcpy(acc->anr.stitch.pyramid, acc_old->anr.stitch.pyramid,
2340                        sizeof(acc->anr.stitch.pyramid));
2341         } else {
2342                 /* Calculate from scratch */
2343                 acc->anr = imgu_css_anr_defaults;
2344         }
2345 
2346         /* Always enabled */
2347         acc->anr.search.enable = 1;
2348         acc->anr.transform.enable = 1;
2349         acc->anr.tile2strm.enable = 1;
2350         acc->anr.tile2strm.frame_width =
2351                 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2352         acc->anr.search.frame_width = acc->anr.tile2strm.frame_width;
2353         acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width;
2354         acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2355         acc->anr.search.frame_height = acc->anr.tile2strm.frame_height;
2356         acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height;
2357 
2358         width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2359         height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2360 
2361         if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET)
2362                 acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width;
2363         if (acc->anr.transform.xreset < IPU3_UAPI_ANR_MIN_RESET)
2364                 acc->anr.transform.xreset = IPU3_UAPI_ANR_MIN_RESET;
2365 
2366         if (acc->anr.transform.yreset + height > IPU3_UAPI_ANR_MAX_RESET)
2367                 acc->anr.transform.yreset = IPU3_UAPI_ANR_MAX_RESET - height;
2368         if (acc->anr.transform.yreset < IPU3_UAPI_ANR_MIN_RESET)
2369                 acc->anr.transform.yreset = IPU3_UAPI_ANR_MIN_RESET;
2370 
2371         /* acc_param: awb_fr_config */
2372 
2373         if (use && use->acc_awb_fr) {
2374                 /* Take values from user */
2375                 acc->awb_fr.config = acc_user->awb_fr;
2376         } else if (acc_old) {
2377                 /* Use old value */
2378                 acc->awb_fr.config = acc_old->awb_fr.config;
2379         } else {
2380                 /* Set from scratch */
2381                 acc->awb_fr.config = imgu_css_awb_fr_defaults;
2382         }
2383 
2384         imgu_css_grid_end_calc(&acc->awb_fr.config.grid_cfg);
2385 
2386         if (acc->awb_fr.config.grid_cfg.width <= 0)
2387                 return -EINVAL;
2388 
2389         acc->awb_fr.config.grid_cfg.height_per_slice =
2390                 IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET /
2391                 acc->awb_fr.config.grid_cfg.width;
2392 
2393         for (i = 0; i < stripes; i++)
2394                 acc->awb_fr.stripes[i] = acc->awb_fr.config;
2395 
2396         if (acc->awb_fr.config.grid_cfg.x_start >=
2397             acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2398                 /* Enable only for rightmost stripe, disable left */
2399                 acc->awb_fr.stripes[0].grid_cfg.y_start &=
2400                                         ~IPU3_UAPI_GRID_Y_START_EN;
2401         } else if (acc->awb_fr.config.grid_cfg.x_end <=
2402                    acc->stripe.bds_out_stripes[0].width - min_overlap) {
2403                 /* Enable only for leftmost stripe, disable right */
2404                 acc->awb_fr.stripes[1].grid_cfg.y_start &=
2405                                         ~IPU3_UAPI_GRID_Y_START_EN;
2406         } else {
2407                 /* Enable for both stripes */
2408                 u16 end; /* width for grid end */
2409 
2410                 acc->awb_fr.stripes[0].grid_cfg.width =
2411                         (acc->stripe.bds_out_stripes[0].width - min_overlap -
2412                          acc->awb_fr.config.grid_cfg.x_start + 1) >>
2413                         acc->awb_fr.config.grid_cfg.block_width_log2;
2414                 acc->awb_fr.stripes[1].grid_cfg.width =
2415                         acc->awb_fr.config.grid_cfg.width -
2416                         acc->awb_fr.stripes[0].grid_cfg.width;
2417 
2418                 b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2;
2419                 end = imgu_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start,
2420                                         acc->awb_fr.stripes[0].grid_cfg.width,
2421                                         b_w_log2);
2422                 acc->awb_fr.stripes[0].grid_cfg.x_end = end;
2423 
2424                 acc->awb_fr.stripes[1].grid_cfg.x_start =
2425                         (acc->awb_fr.stripes[0].grid_cfg.x_end + 1 -
2426                          acc->stripe.down_scaled_stripes[1].offset) &
2427                         IPU3_UAPI_GRID_START_MASK;
2428                 b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2;
2429                 end = imgu_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start,
2430                                         acc->awb_fr.stripes[1].grid_cfg.width,
2431                                         b_w_log2);
2432                 acc->awb_fr.stripes[1].grid_cfg.x_end = end;
2433 
2434                 /*
2435                  * To reduce complexity of debubbling and loading
2436                  * statistics fix grid_height_per_slice to 1 for both
2437                  * stripes.
2438                  */
2439                 for (i = 0; i < stripes; i++)
2440                         acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1;
2441         }
2442 
2443         if (imgu_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr))
2444                 return -EINVAL;
2445 
2446         /* acc_param: ae_config */
2447 
2448         if (use && use->acc_ae) {
2449                 /* Take values from user */
2450                 acc->ae.grid_cfg = acc_user->ae.grid_cfg;
2451                 acc->ae.ae_ccm = acc_user->ae.ae_ccm;
2452                 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2453                         acc->ae.weights[i] = acc_user->ae.weights[i];
2454         } else if (acc_old) {
2455                 /* Use old value */
2456                 acc->ae.grid_cfg = acc_old->ae.grid_cfg;
2457                 acc->ae.ae_ccm = acc_old->ae.ae_ccm;
2458                 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2459                         acc->ae.weights[i] = acc_old->ae.weights[i];
2460         } else {
2461                 /* Set from scratch */
2462                 static const struct ipu3_uapi_ae_weight_elem
2463                         weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 };
2464 
2465                 acc->ae.grid_cfg = imgu_css_ae_grid_defaults;
2466                 acc->ae.ae_ccm = imgu_css_ae_ccm_defaults;
2467                 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2468                         acc->ae.weights[i] = weight_def;
2469         }
2470 
2471         b_w_log2 = acc->ae.grid_cfg.block_width_log2;
2472         acc->ae.grid_cfg.x_end = imgu_css_grid_end(acc->ae.grid_cfg.x_start,
2473                                                    acc->ae.grid_cfg.width,
2474                                                    b_w_log2);
2475         b_w_log2 = acc->ae.grid_cfg.block_height_log2;
2476         acc->ae.grid_cfg.y_end = imgu_css_grid_end(acc->ae.grid_cfg.y_start,
2477                                                    acc->ae.grid_cfg.height,
2478                                                    b_w_log2);
2479 
2480         for (i = 0; i < stripes; i++)
2481                 acc->ae.stripes[i].grid = acc->ae.grid_cfg;
2482 
2483         if (acc->ae.grid_cfg.x_start >=
2484             acc->stripe.down_scaled_stripes[1].offset) {
2485                 /* Enable only for rightmost stripe, disable left */
2486                 acc->ae.stripes[0].grid.ae_en = 0;
2487         } else if (acc->ae.grid_cfg.x_end <=
2488                    acc->stripe.bds_out_stripes[0].width) {
2489                 /* Enable only for leftmost stripe, disable right */
2490                 acc->ae.stripes[1].grid.ae_en = 0;
2491         } else {
2492                 /* Enable for both stripes */
2493                 u8 b_w_log2;
2494 
2495                 acc->ae.stripes[0].grid.width =
2496                         (acc->stripe.bds_out_stripes[0].width -
2497                          acc->ae.grid_cfg.x_start + 1) >>
2498                         acc->ae.grid_cfg.block_width_log2;
2499 
2500                 acc->ae.stripes[1].grid.width =
2501                         acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width;
2502 
2503                 b_w_log2 = acc->ae.stripes[0].grid.block_width_log2;
2504                 acc->ae.stripes[0].grid.x_end =
2505                         imgu_css_grid_end(acc->ae.stripes[0].grid.x_start,
2506                                           acc->ae.stripes[0].grid.width,
2507                                           b_w_log2);
2508 
2509                 acc->ae.stripes[1].grid.x_start =
2510                         (acc->ae.stripes[0].grid.x_end + 1 -
2511                          acc->stripe.down_scaled_stripes[1].offset) &
2512                         IPU3_UAPI_GRID_START_MASK;
2513                 b_w_log2 = acc->ae.stripes[1].grid.block_width_log2;
2514                 acc->ae.stripes[1].grid.x_end =
2515                         imgu_css_grid_end(acc->ae.stripes[1].grid.x_start,
2516                                           acc->ae.stripes[1].grid.width,
2517                                           b_w_log2);
2518         }
2519 
2520         /* acc_param: af_config */
2521 
2522         if (use && use->acc_af) {
2523                 /* Take values from user */
2524                 acc->af.config.filter_config = acc_user->af.filter_config;
2525                 acc->af.config.grid_cfg = acc_user->af.grid_cfg;
2526         } else if (acc_old) {
2527                 /* Use old value */
2528                 acc->af.config = acc_old->af.config;
2529         } else {
2530                 /* Set from scratch */
2531                 acc->af.config.filter_config =
2532                                 imgu_css_af_defaults.filter_config;
2533                 acc->af.config.grid_cfg = imgu_css_af_defaults.grid_cfg;
2534         }
2535 
2536         imgu_css_grid_end_calc(&acc->af.config.grid_cfg);
2537 
2538         if (acc->af.config.grid_cfg.width <= 0)
2539                 return -EINVAL;
2540 
2541         acc->af.config.grid_cfg.height_per_slice =
2542                 IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width;
2543         acc->af.config.frame_size.width =
2544                 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2545         acc->af.config.frame_size.height =
2546                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2547 
2548         if (acc->stripe.bds_out_stripes[0].width <= min_overlap)
2549                 return -EINVAL;
2550 
2551         for (i = 0; i < stripes; i++) {
2552                 acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg;
2553                 acc->af.stripes[i].frame_size.height =
2554                                 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2555                 acc->af.stripes[i].frame_size.width =
2556                         acc->stripe.bds_out_stripes[i].width;
2557         }
2558 
2559         if (acc->af.config.grid_cfg.x_start >=
2560             acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2561                 /* Enable only for rightmost stripe, disable left */
2562                 acc->af.stripes[0].grid_cfg.y_start &=
2563                         ~IPU3_UAPI_GRID_Y_START_EN;
2564         } else if (acc->af.config.grid_cfg.x_end <=
2565                    acc->stripe.bds_out_stripes[0].width - min_overlap) {
2566                 /* Enable only for leftmost stripe, disable right */
2567                 acc->af.stripes[1].grid_cfg.y_start &=
2568                         ~IPU3_UAPI_GRID_Y_START_EN;
2569         } else {
2570                 /* Enable for both stripes */
2571 
2572                 acc->af.stripes[0].grid_cfg.width =
2573                         (acc->stripe.bds_out_stripes[0].width - min_overlap -
2574                          acc->af.config.grid_cfg.x_start + 1) >>
2575                         acc->af.config.grid_cfg.block_width_log2;
2576                 acc->af.stripes[1].grid_cfg.width =
2577                         acc->af.config.grid_cfg.width -
2578                         acc->af.stripes[0].grid_cfg.width;
2579 
2580                 b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2;
2581                 acc->af.stripes[0].grid_cfg.x_end =
2582                         imgu_css_grid_end(acc->af.stripes[0].grid_cfg.x_start,
2583                                           acc->af.stripes[0].grid_cfg.width,
2584                                           b_w_log2);
2585 
2586                 acc->af.stripes[1].grid_cfg.x_start =
2587                         (acc->af.stripes[0].grid_cfg.x_end + 1 -
2588                          acc->stripe.down_scaled_stripes[1].offset) &
2589                         IPU3_UAPI_GRID_START_MASK;
2590 
2591                 b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2;
2592                 acc->af.stripes[1].grid_cfg.x_end =
2593                         imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start,
2594                                           acc->af.stripes[1].grid_cfg.width,
2595                                           b_w_log2);
2596 
2597                 /*
2598                  * To reduce complexity of debubbling and loading statistics
2599                  * fix grid_height_per_slice to 1 for both stripes
2600                  */
2601                 for (i = 0; i < stripes; i++)
2602                         acc->af.stripes[i].grid_cfg.height_per_slice = 1;
2603         }
2604 
2605         if (imgu_css_af_ops_calc(css, pipe, &acc->af))
2606                 return -EINVAL;
2607 
2608         /* acc_param: awb_config */
2609 
2610         if (use && use->acc_awb) {
2611                 /* Take values from user */
2612                 acc->awb.config = acc_user->awb.config;
2613         } else if (acc_old) {
2614                 /* Use old value */
2615                 acc->awb.config = acc_old->awb.config;
2616         } else {
2617                 /* Set from scratch */
2618                 acc->awb.config = imgu_css_awb_defaults;
2619         }
2620 
2621         if (acc->awb.config.grid.width <= 0)
2622                 return -EINVAL;
2623 
2624         acc->awb.config.grid.height_per_slice =
2625                 IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width,
2626         imgu_css_grid_end_calc(&acc->awb.config.grid);
2627 
2628         for (i = 0; i < stripes; i++)
2629                 acc->awb.stripes[i] = acc->awb.config;
2630 
2631         if (acc->awb.config.grid.x_start >=
2632             acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2633                 /* Enable only for rightmost stripe, disable left */
2634                 acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
2635         } else if (acc->awb.config.grid.x_end <=
2636                    acc->stripe.bds_out_stripes[0].width - min_overlap) {
2637                 /* Enable only for leftmost stripe, disable right */
2638                 acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
2639         } else {
2640                 /* Enable for both stripes */
2641 
2642                 acc->awb.stripes[0].grid.width =
2643                         (acc->stripe.bds_out_stripes[0].width -
2644                          acc->awb.config.grid.x_start + 1) >>
2645                         acc->awb.config.grid.block_width_log2;
2646                 acc->awb.stripes[1].grid.width = acc->awb.config.grid.width -
2647                                 acc->awb.stripes[0].grid.width;
2648 
2649                 b_w_log2 = acc->awb.stripes[0].grid.block_width_log2;
2650                 acc->awb.stripes[0].grid.x_end =
2651                         imgu_css_grid_end(acc->awb.stripes[0].grid.x_start,
2652                                           acc->awb.stripes[0].grid.width,
2653                                           b_w_log2);
2654 
2655                 acc->awb.stripes[1].grid.x_start =
2656                         (acc->awb.stripes[0].grid.x_end + 1 -
2657                          acc->stripe.down_scaled_stripes[1].offset) &
2658                         IPU3_UAPI_GRID_START_MASK;
2659 
2660                 b_w_log2 = acc->awb.stripes[1].grid.block_width_log2;
2661                 acc->awb.stripes[1].grid.x_end =
2662                         imgu_css_grid_end(acc->awb.stripes[1].grid.x_start,
2663                                           acc->awb.stripes[1].grid.width,
2664                                           b_w_log2);
2665 
2666                 /*
2667                  * To reduce complexity of debubbling and loading statistics
2668                  * fix grid_height_per_slice to 1 for both stripes
2669                  */
2670                 for (i = 0; i < stripes; i++)
2671                         acc->awb.stripes[i].grid.height_per_slice = 1;
2672         }
2673 
2674         if (imgu_css_awb_ops_calc(css, pipe, &acc->awb))
2675                 return -EINVAL;
2676 
2677         return 0;
2678 }
2679 
2680 /*
2681  * Fill the indicated structure in `new_binary_params' from the possible
2682  * sources based on `use_user' flag: if the flag is false, copy from
2683  * `old_binary_params', or if the flag is true, copy from `user_setting'
2684  * and return NULL (or error pointer on error).
2685  * If the flag is false and `old_binary_params' is NULL, return pointer
2686  * to the structure inside `new_binary_params'. In that case the caller
2687  * should calculate and fill the structure from scratch.
2688  */
2689 static void *imgu_css_cfg_copy(struct imgu_css *css,
2690                                unsigned int pipe, bool use_user,
2691                                void *user_setting, void *old_binary_params,
2692                                void *new_binary_params,
2693                                enum imgu_abi_memories m,
2694                                struct imgu_fw_isp_parameter *par,
2695                                size_t par_size)
2696 {
2697         const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2698         void *new_setting, *old_setting;
2699 
2700         new_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par,
2701                                                   par_size, new_binary_params);
2702         if (!new_setting)
2703                 return ERR_PTR(-EPROTO);        /* Corrupted firmware */
2704 
2705         if (use_user) {
2706                 /* Take new user parameters */
2707                 memcpy(new_setting, user_setting, par_size);
2708         } else if (old_binary_params) {
2709                 /* Take previous value */
2710                 old_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par,
2711                                                           par_size,
2712                                                           old_binary_params);
2713                 if (!old_setting)
2714                         return ERR_PTR(-EPROTO);
2715                 memcpy(new_setting, old_setting, par_size);
2716         } else {
2717                 return new_setting;     /* Need to calculate */
2718         }
2719 
2720         return NULL;            /* Copied from other value */
2721 }
2722 
2723 /*
2724  * Configure VMEM0 parameters (late binding parameters).
2725  */
2726 int imgu_css_cfg_vmem0(struct imgu_css *css, unsigned int pipe,
2727                        struct ipu3_uapi_flags *use,
2728                        void *vmem0, void *vmem0_old,
2729                        struct ipu3_uapi_params *user)
2730 {
2731         const struct imgu_fw_info *bi =
2732                 &css->fwp->binary_header[css->pipes[pipe].bindex];
2733         struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
2734                 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
2735         struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL;
2736         struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem = NULL;
2737         struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem = NULL;
2738         const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2739         const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0;
2740         unsigned int i;
2741 
2742         /* Configure VMEM0 */
2743 
2744         memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
2745 
2746         /* Configure Linearization VMEM0 parameters */
2747 
2748         lin_vmem = imgu_css_cfg_copy(css, pipe, use && use->lin_vmem_params,
2749                                      &user->lin_vmem_params, vmem0_old, vmem0,
2750                                      m, &pofs->vmem.lin, sizeof(*lin_vmem));
2751         if (!IS_ERR_OR_NULL(lin_vmem)) {
2752                 /* Generate parameter from scratch */
2753                 for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) {
2754                         lin_vmem->lin_lutlow_gr[i] = 32 * i;
2755                         lin_vmem->lin_lutlow_r[i] = 32 * i;
2756                         lin_vmem->lin_lutlow_b[i] = 32 * i;
2757                         lin_vmem->lin_lutlow_gb[i] = 32 * i;
2758 
2759                         lin_vmem->lin_lutdif_gr[i] = 32;
2760                         lin_vmem->lin_lutdif_r[i] = 32;
2761                         lin_vmem->lin_lutdif_b[i] = 32;
2762                         lin_vmem->lin_lutdif_gb[i] = 32;
2763                 }
2764         }
2765 
2766         /* Configure TNR3 VMEM parameters */
2767         if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
2768                 tnr_vmem = imgu_css_cfg_copy(css, pipe,
2769                                              use && use->tnr3_vmem_params,
2770                                              &user->tnr3_vmem_params,
2771                                              vmem0_old, vmem0, m,
2772                                              &pofs->vmem.tnr3,
2773                                              sizeof(*tnr_vmem));
2774                 if (!IS_ERR_OR_NULL(tnr_vmem)) {
2775                         /* Generate parameter from scratch */
2776                         for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++)
2777                                 tnr_vmem->sigma[i] = 256;
2778                 }
2779         }
2780         i = IPU3_UAPI_ISP_TNR3_VMEM_LEN;
2781 
2782         /* Configure XNR3 VMEM parameters */
2783 
2784         xnr_vmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params,
2785                                      &user->xnr3_vmem_params, vmem0_old, vmem0,
2786                                      m, &pofs->vmem.xnr3, sizeof(*xnr_vmem));
2787         if (!IS_ERR_OR_NULL(xnr_vmem)) {
2788                 xnr_vmem->x[i] = imgu_css_xnr3_vmem_defaults.x
2789                         [i % IMGU_XNR3_VMEM_LUT_LEN];
2790                 xnr_vmem->a[i] = imgu_css_xnr3_vmem_defaults.a
2791                         [i % IMGU_XNR3_VMEM_LUT_LEN];
2792                 xnr_vmem->b[i] = imgu_css_xnr3_vmem_defaults.b
2793                         [i % IMGU_XNR3_VMEM_LUT_LEN];
2794                 xnr_vmem->c[i] = imgu_css_xnr3_vmem_defaults.c
2795                         [i % IMGU_XNR3_VMEM_LUT_LEN];
2796         }
2797 
2798         return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ?
2799                 -EPROTO : 0;
2800 }
2801 
2802 /*
2803  * Configure DMEM0 parameters (late binding parameters).
2804  */
2805 int imgu_css_cfg_dmem0(struct imgu_css *css, unsigned int pipe,
2806                        struct ipu3_uapi_flags *use,
2807                        void *dmem0, void *dmem0_old,
2808                        struct ipu3_uapi_params *user)
2809 {
2810         struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
2811         const struct imgu_fw_info *bi =
2812                 &css->fwp->binary_header[css_pipe->bindex];
2813         struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
2814                 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
2815 
2816         struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL;
2817         struct ipu3_uapi_isp_xnr3_params *xnr_dmem;
2818 
2819         const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2820         const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0;
2821 
2822         /* Configure DMEM0 */
2823 
2824         memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
2825 
2826         /* Configure TNR3 DMEM0 parameters */
2827         if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
2828                 tnr_dmem = imgu_css_cfg_copy(css, pipe,
2829                                              use && use->tnr3_dmem_params,
2830                                              &user->tnr3_dmem_params,
2831                                              dmem0_old, dmem0, m,
2832                                              &pofs->dmem.tnr3,
2833                                              sizeof(*tnr_dmem));
2834                 if (!IS_ERR_OR_NULL(tnr_dmem)) {
2835                         /* Generate parameter from scratch */
2836                         tnr_dmem->knee_y1 = 768;
2837                         tnr_dmem->knee_y2 = 1280;
2838                 }
2839         }
2840 
2841         /* Configure XNR3 DMEM0 parameters */
2842 
2843         xnr_dmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params,
2844                                      &user->xnr3_dmem_params, dmem0_old, dmem0,
2845                                      m, &pofs->dmem.xnr3, sizeof(*xnr_dmem));
2846         if (!IS_ERR_OR_NULL(xnr_dmem)) {
2847                 /* Generate parameter from scratch */
2848                 xnr_dmem->alpha.y0 = 2047;
2849                 xnr_dmem->alpha.u0 = 2047;
2850                 xnr_dmem->alpha.v0 = 2047;
2851         }
2852 
2853         return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0;
2854 }
2855 
2856 /* Generate unity morphing table without morphing effect */
2857 void imgu_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc,
2858                             int frame_in_x, int frame_in_y,
2859                             int frame_out_x, int frame_out_y,
2860                             int env_w, int env_h)
2861 {
2862         static const unsigned int FRAC_BITS = IMGU_ABI_GDC_FRAC_BITS;
2863         static const unsigned int XMEM_ALIGN = 1 << 4;
2864         const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1);
2865         static const unsigned int BCI_ENV = 4;
2866         static const unsigned int BYP = 2;      /* Bytes per pixel */
2867         const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + env_w + 1;
2868         const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + env_h + 1;
2869 
2870         struct imgu_abi_gdc_warp_param gdc_luma, gdc_chroma;
2871 
2872         unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x,
2873                                                    IMGU_DVS_BLOCK_W), 2);
2874         unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H);
2875         unsigned int y0, x0, x1, x, y;
2876 
2877         /* Global luma settings */
2878         gdc_luma.origin_x = 0;
2879         gdc_luma.origin_y = 0;
2880         gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << FRAC_BITS;
2881         gdc_luma.p0_y = 0;
2882         gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
2883         gdc_luma.p1_y = gdc_luma.p0_y;
2884         gdc_luma.p2_x = gdc_luma.p0_x;
2885         gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << FRAC_BITS);
2886         gdc_luma.p3_x = gdc_luma.p1_x;
2887         gdc_luma.p3_y = gdc_luma.p2_y;
2888 
2889         gdc_luma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV +
2890                                         OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK);
2891         gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width,
2892                                                  IPU3_UAPI_ISP_VEC_ELEMS);
2893         gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width,
2894                                                  IMGU_ABI_ISP_DDR_WORD_BYTES /
2895                                                  BYP);
2896         gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV;
2897         gdc_luma.padding = 0;
2898 
2899         /* Global chroma settings */
2900         gdc_chroma.origin_x = 0;
2901         gdc_chroma.origin_y = 0;
2902         gdc_chroma.p0_x = (OFFSET_X / 2 - (OFFSET_X / 2 & XMEM_ALIGN_MASK)) <<
2903                            FRAC_BITS;
2904         gdc_chroma.p0_y = 0;
2905         gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
2906         gdc_chroma.p1_y = gdc_chroma.p0_y;
2907         gdc_chroma.p2_x = gdc_chroma.p0_x;
2908         gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << FRAC_BITS);
2909         gdc_chroma.p3_x = gdc_chroma.p1_x;
2910         gdc_chroma.p3_y = gdc_chroma.p2_y;
2911 
2912         gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV;
2913         gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width,
2914                                                    IPU3_UAPI_ISP_VEC_ELEMS);
2915         gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width,
2916                                                    IMGU_ABI_ISP_DDR_WORD_BYTES /
2917                                                    BYP);
2918         gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV;
2919         gdc_chroma.padding = 0;
2920 
2921         /* Calculate block offsets for luma and chroma */
2922         for (y0 = 0; y0 < blocks_y; y0++) {
2923                 for (x0 = 0; x0 < blocks_x / 2; x0++) {
2924                         for (x1 = 0; x1 < 2; x1++) {
2925                                 /* Luma blocks */
2926                                 x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X;
2927                                 x &= XMEM_ALIGN_MASK;
2928                                 y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y;
2929                                 *gdc = gdc_luma;
2930                                 gdc->in_addr_offset =
2931                                         (y * frame_in_x + x) * BYP;
2932                                 gdc++;
2933                         }
2934 
2935                         /* Chroma block */
2936                         x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2;
2937                         x &= XMEM_ALIGN_MASK;
2938                         y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2;
2939                         *gdc = gdc_chroma;
2940                         gdc->in_addr_offset = (y * frame_in_x + x) * BYP;
2941                         gdc++;
2942                 }
2943         }
2944 }

/* [<][>][^][v][top][bottom][index][help] */