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