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
imgu_css_scaler_get_exp(unsigned int counter,unsigned int divider)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
imgu_css_scaler_setup_lut(unsigned int taps,unsigned int input_width,unsigned int output_width,int phase_step_correction,const int * coeffs,unsigned int coeffs_size,s8 coeff_lut[],struct imgu_css_scaler_info * info)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
imgu_css_scaler_calc_scaled_output(unsigned int input,struct imgu_css_scaler_info * info)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
imgu_css_scaler_calc(u32 input_width,u32 input_height,u32 target_width,u32 target_height,struct imgu_abi_osys_config * cfg,struct imgu_css_scaler_info * info_luma,struct imgu_css_scaler_info * info_chroma,unsigned int * output_width,unsigned int * output_height,unsigned int * procmode)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
imgu_css_osys_set_format(enum imgu_abi_frame_format host_format,unsigned int * osys_format,unsigned int * osys_tiling)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 */
imgu_css_osys_calc_stripe_offset(int stripe_offset_out,int fir_phases,int phase_init,int phase_step,int pad_left)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 */
imgu_css_osys_calc_stripe_phase_init(int stripe_offset_out,int fir_phases,int phase_init,int phase_step,int pad_left)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 */
imgu_css_osys_calc_inp_stripe_width(int stripe_width_out,int fir_phases,int phase_init,int phase_step,int fir_taps,int pad_left,int pad_right)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 */
imgu_css_osys_out_stripe_width(int stripe_width_inp,int fir_phases,int phase_init,int phase_step,int fir_taps,int pad_left,int pad_right,int column_offset)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 */
imgu_css_osys_calc_frame_and_stripe_params(struct imgu_css * css,unsigned int stripes,struct imgu_abi_osys_config * osys,struct imgu_css_scaler_info * scaler_luma,struct imgu_css_scaler_info * scaler_chroma,struct imgu_css_frame_params frame_params[],struct imgu_css_stripe_params stripe_params[],unsigned int pipe)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 int pin_scale = 0;
775 /*Input resolution */
776
777 stripe_params[s].input_width = stripe_input_width_y;
778 stripe_params[s].input_height = reso.input_height;
779
780 for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) {
781 if (frame_params[i].scaled) {
782 /*
783 * Output stripe resolution and offset
784 * as produced by the scaler; actual
785 * output resolution may be slightly
786 * smaller.
787 */
788 stripe_params[s].output_width[i] =
789 stripe_output_width_y;
790 stripe_params[s].output_height[i] =
791 reso.pin_height[i];
792 stripe_params[s].output_offset[i] =
793 stripe_offset_out_y;
794
795 pin_scale += frame_params[i].scaled;
796 } else {
797 /* Unscaled pin */
798 stripe_params[s].output_width[i] =
799 stripe_params[s].input_width;
800 stripe_params[s].output_height[i] =
801 stripe_params[s].input_height;
802 stripe_params[s].output_offset[i] =
803 stripe_offset_blk_y;
804 }
805 }
806
807 /* If no pin use scale, we use BYPASS mode */
808 stripe_params[s].processing_mode = procmode;
809 stripe_params[s].phase_step = scaler_luma->phase_step;
810 stripe_params[s].exp_shift = scaler_luma->exp_shift;
811 stripe_params[s].phase_init_left_y =
812 stripe_phase_init_y;
813 stripe_params[s].phase_init_left_uv =
814 stripe_phase_init_uv;
815 stripe_params[s].phase_init_top_y =
816 scaler_luma->phase_init;
817 stripe_params[s].phase_init_top_uv =
818 scaler_chroma->phase_init;
819 stripe_params[s].pad_left_y = stripe_pad_left_y;
820 stripe_params[s].pad_left_uv = stripe_pad_left_uv;
821 stripe_params[s].pad_right_y = stripe_pad_right_y;
822 stripe_params[s].pad_right_uv = stripe_pad_right_uv;
823 stripe_params[s].pad_top_y = scaler_luma->pad_left;
824 stripe_params[s].pad_top_uv = scaler_chroma->pad_left;
825 stripe_params[s].pad_bottom_y = scaler_luma->pad_right;
826 stripe_params[s].pad_bottom_uv =
827 scaler_chroma->pad_right;
828 stripe_params[s].crop_left_y = stripe_crop_left_y;
829 stripe_params[s].crop_top_y = scaler_luma->crop_top;
830 stripe_params[s].crop_left_uv = stripe_crop_left_uv;
831 stripe_params[s].crop_top_uv = scaler_chroma->crop_top;
832 stripe_params[s].start_column_y = stripe_offset_col_y;
833 stripe_params[s].start_column_uv = stripe_offset_col_uv;
834 stripe_params[s].chunk_width = reso.chunk_width;
835 stripe_params[s].chunk_height = reso.chunk_height;
836 stripe_params[s].block_width = reso.block_width;
837 stripe_params[s].block_height = reso.block_height;
838 }
839 }
840
841 return 0;
842 }
843
844 /*
845 * This function configures the Output Formatter System, given the number of
846 * stripes, scaler luma and chrome parameters
847 */
imgu_css_osys_calc(struct imgu_css * css,unsigned int pipe,unsigned int stripes,struct imgu_abi_osys_config * osys,struct imgu_css_scaler_info * scaler_luma,struct imgu_css_scaler_info * scaler_chroma,struct imgu_abi_stripes block_stripes[])848 static int imgu_css_osys_calc(struct imgu_css *css, unsigned int pipe,
849 unsigned int stripes,
850 struct imgu_abi_osys_config *osys,
851 struct imgu_css_scaler_info *scaler_luma,
852 struct imgu_css_scaler_info *scaler_chroma,
853 struct imgu_abi_stripes block_stripes[])
854 {
855 struct imgu_css_frame_params frame_params[IMGU_ABI_OSYS_PINS];
856 struct imgu_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES];
857 struct imgu_abi_osys_formatter_params *param;
858 unsigned int pin, s;
859 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
860
861 memset(osys, 0, sizeof(*osys));
862
863 /* Compute the frame and stripe params */
864 if (imgu_css_osys_calc_frame_and_stripe_params(css, stripes, osys,
865 scaler_luma,
866 scaler_chroma,
867 frame_params,
868 stripe_params, pipe))
869 return -EINVAL;
870
871 /* Output formatter system parameters */
872
873 for (s = 0; s < stripes; s++) {
874 struct imgu_abi_osys_scaler_params *scaler =
875 &osys->scaler[s].param;
876 int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT;
877 int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP;
878
879 /* OUTPUT 0 / PIN 0 is only Scaler output */
880 scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
881
882 /*
883 * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
884 * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) /
885 * (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
886 * = 2 * 64 / 32 = 4
887 */
888 scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE;
889 /*
890 * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size)
891 * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) +
892 * (VMEM1_y_size / 4)
893 * = (VMEM1_y_size) + (VMEM1_y_size / 4) +
894 * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4
895 * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
896 */
897 scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
898 scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
899 IMGU_VMEM1_U_OFFSET;
900 scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
901 IMGU_VMEM1_V_OFFSET;
902 scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE;
903 scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
904 scaler->inp_buf_chunk_width = stripe_params[s].chunk_width;
905 scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS;
906
907 /* Output buffers */
908 scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
909 scaler->out_buf_y_line_stride = stripe_params[s].block_width /
910 IMGU_VMEM1_ELEMS_PER_VEC;
911 scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
912 scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
913 IMGU_VMEM1_U_OFFSET;
914 scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
915 IMGU_VMEM1_V_OFFSET;
916 scaler->out_buf_uv_line_stride = stripe_params[s].block_width /
917 IMGU_VMEM1_ELEMS_PER_VEC / 2;
918 scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
919 scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS;
920
921 /* Intermediate buffers */
922 scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR;
923 scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE;
924 scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR;
925 scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR;
926 scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE;
927 scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK;
928 scaler->int_buf_chunk_width = stripe_params[s].chunk_height;
929 scaler->int_buf_chunk_height = stripe_params[s].block_width;
930
931 /* Context buffers */
932 scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR;
933 scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR;
934 scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR;
935 scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR;
936 scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR;
937 scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR;
938
939 /* Addresses for release-input and process-output tokens */
940 scaler->release_inp_buf_addr = fifo_addr_ack;
941 scaler->release_inp_buf_en = 1;
942 scaler->release_out_buf_en = 1;
943 scaler->process_out_buf_addr = fifo_addr_fmt;
944
945 /* Settings dimensions, padding, cropping */
946 scaler->input_image_y_width = stripe_params[s].input_width;
947 scaler->input_image_y_height = stripe_params[s].input_height;
948 scaler->input_image_y_start_column =
949 stripe_params[s].start_column_y;
950 scaler->input_image_uv_start_column =
951 stripe_params[s].start_column_uv;
952 scaler->input_image_y_left_pad = stripe_params[s].pad_left_y;
953 scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv;
954 scaler->input_image_y_right_pad = stripe_params[s].pad_right_y;
955 scaler->input_image_uv_right_pad =
956 stripe_params[s].pad_right_uv;
957 scaler->input_image_y_top_pad = stripe_params[s].pad_top_y;
958 scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv;
959 scaler->input_image_y_bottom_pad =
960 stripe_params[s].pad_bottom_y;
961 scaler->input_image_uv_bottom_pad =
962 stripe_params[s].pad_bottom_uv;
963 scaler->processing_mode = stripe_params[s].processing_mode;
964 scaler->scaling_ratio = stripe_params[s].phase_step;
965 scaler->y_left_phase_init = stripe_params[s].phase_init_left_y;
966 scaler->uv_left_phase_init =
967 stripe_params[s].phase_init_left_uv;
968 scaler->y_top_phase_init = stripe_params[s].phase_init_top_y;
969 scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv;
970 scaler->coeffs_exp_shift = stripe_params[s].exp_shift;
971 scaler->out_y_left_crop = stripe_params[s].crop_left_y;
972 scaler->out_uv_left_crop = stripe_params[s].crop_left_uv;
973 scaler->out_y_top_crop = stripe_params[s].crop_top_y;
974 scaler->out_uv_top_crop = stripe_params[s].crop_top_uv;
975
976 for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
977 int in_fifo_addr;
978 int out_fifo_addr;
979 int block_width_vecs;
980 int input_width_s;
981 int input_width_vecs;
982 int input_buf_y_st_addr;
983 int input_buf_u_st_addr;
984 int input_buf_v_st_addr;
985 int input_buf_y_line_stride;
986 int input_buf_uv_line_stride;
987 int output_buf_y_line_stride;
988 int output_buf_uv_line_stride;
989 int output_buf_nr_y_lines;
990 int block_height;
991 int block_width;
992 struct imgu_abi_osys_frame_params *fr_pr;
993
994 fr_pr = &osys->frame[pin].param;
995
996 /* Frame parameters */
997 fr_pr->enable = frame_params[pin].enable;
998 fr_pr->format = frame_params[pin].format;
999 fr_pr->mirror = frame_params[pin].mirror;
1000 fr_pr->flip = frame_params[pin].flip;
1001 fr_pr->tiling = frame_params[pin].tiling;
1002 fr_pr->width = frame_params[pin].width;
1003 fr_pr->height = frame_params[pin].height;
1004 fr_pr->stride = frame_params[pin].stride;
1005 fr_pr->scaled = frame_params[pin].scaled;
1006
1007 /* Stripe parameters */
1008 osys->stripe[s].crop_top[pin] =
1009 frame_params[pin].crop_top;
1010 osys->stripe[s].input_width =
1011 stripe_params[s].input_width;
1012 osys->stripe[s].input_height =
1013 stripe_params[s].input_height;
1014 osys->stripe[s].block_height =
1015 stripe_params[s].block_height;
1016 osys->stripe[s].block_width =
1017 stripe_params[s].block_width;
1018 osys->stripe[s].output_width[pin] =
1019 stripe_params[s].output_width[pin];
1020 osys->stripe[s].output_height[pin] =
1021 stripe_params[s].output_height[pin];
1022
1023 if (s == 0) {
1024 /* Only first stripe should do left cropping */
1025 osys->stripe[s].crop_left[pin] =
1026 frame_params[pin].crop_left;
1027 osys->stripe[s].output_offset[pin] =
1028 stripe_params[s].output_offset[pin];
1029 } else {
1030 /*
1031 * Stripe offset for other strips should be
1032 * adjusted according to the cropping done
1033 * at the first strip
1034 */
1035 osys->stripe[s].crop_left[pin] = 0;
1036 osys->stripe[s].output_offset[pin] =
1037 (stripe_params[s].output_offset[pin] -
1038 osys->stripe[0].crop_left[pin]);
1039 }
1040
1041 if (!frame_params[pin].enable)
1042 continue;
1043
1044 /* Formatter: configurations */
1045
1046 /*
1047 * Get the dimensions of the input blocks of the
1048 * formatter, which is the same as the output
1049 * blocks of the scaler.
1050 */
1051 if (frame_params[pin].scaled) {
1052 block_height = stripe_params[s].block_height;
1053 block_width = stripe_params[s].block_width;
1054 } else {
1055 block_height = IMGU_OSYS_BLOCK_HEIGHT;
1056 block_width = IMGU_OSYS_BLOCK_WIDTH;
1057 }
1058 block_width_vecs =
1059 block_width / IMGU_VMEM1_ELEMS_PER_VEC;
1060 /*
1061 * The input/output line stride depends on the
1062 * block size.
1063 */
1064 input_buf_y_line_stride = block_width_vecs;
1065 input_buf_uv_line_stride = block_width_vecs / 2;
1066 output_buf_y_line_stride = block_width_vecs;
1067 output_buf_uv_line_stride = block_width_vecs / 2;
1068 output_buf_nr_y_lines = block_height;
1069 if (frame_params[pin].format ==
1070 IMGU_ABI_OSYS_FORMAT_NV12 ||
1071 frame_params[pin].format ==
1072 IMGU_ABI_OSYS_FORMAT_NV21)
1073 output_buf_uv_line_stride =
1074 output_buf_y_line_stride;
1075
1076 /*
1077 * Tiled outputs use a different output buffer
1078 * configuration. The input (= scaler output) block
1079 * width translates to a tile height, and the block
1080 * height to the tile width. The default block size of
1081 * 128x32 maps exactly onto a 4kB tile (512x8) for Y.
1082 * For UV, the tile width is always half.
1083 */
1084 if (frame_params[pin].tiling) {
1085 output_buf_nr_y_lines = 8;
1086 output_buf_y_line_stride = 512 /
1087 IMGU_VMEM1_ELEMS_PER_VEC;
1088 output_buf_uv_line_stride = 256 /
1089 IMGU_VMEM1_ELEMS_PER_VEC;
1090 }
1091
1092 /*
1093 * Store the output buffer line stride. Will be
1094 * used to compute buffer offsets in boundary
1095 * conditions when output blocks are partially
1096 * outside the image.
1097 */
1098 osys->stripe[s].buf_stride[pin] =
1099 output_buf_y_line_stride *
1100 IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS;
1101 if (frame_params[pin].scaled) {
1102 /*
1103 * The input buffs are the intermediate
1104 * buffers (scalers' output)
1105 */
1106 input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
1107 input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
1108 IMGU_VMEM1_U_OFFSET;
1109 input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
1110 IMGU_VMEM1_V_OFFSET;
1111 } else {
1112 /*
1113 * The input bufferss are the buffers
1114 * filled by the SP
1115 */
1116 input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
1117 input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
1118 IMGU_VMEM1_U_OFFSET;
1119 input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
1120 IMGU_VMEM1_V_OFFSET;
1121 }
1122
1123 /*
1124 * The formatter input width must be rounded to
1125 * the block width. Otherwise the formatter will
1126 * not recognize the end of the line, resulting
1127 * in incorrect tiling (system may hang!) and
1128 * possibly other problems.
1129 */
1130 input_width_s =
1131 roundup(stripe_params[s].output_width[pin],
1132 block_width);
1133 input_width_vecs = input_width_s /
1134 IMGU_VMEM1_ELEMS_PER_VEC;
1135 out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
1136 /*
1137 * Process-output tokens must be sent to the SP.
1138 * When scaling, the release-input tokens can be
1139 * sent directly to the scaler, otherwise the
1140 * formatter should send them to the SP.
1141 */
1142 if (frame_params[pin].scaled)
1143 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER;
1144 else
1145 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
1146
1147 /* Formatter */
1148 param = &osys->formatter[s][pin].param;
1149
1150 param->format = frame_params[pin].format;
1151 param->flip = frame_params[pin].flip;
1152 param->mirror = frame_params[pin].mirror;
1153 param->tiling = frame_params[pin].tiling;
1154 param->reduce_range = frame_params[pin].reduce_range;
1155 param->alpha_blending = 0;
1156 param->release_inp_addr = in_fifo_addr;
1157 param->release_inp_en = 1;
1158 param->process_out_buf_addr = out_fifo_addr;
1159 param->image_width_vecs = input_width_vecs;
1160 param->image_height_lines =
1161 stripe_params[s].output_height[pin];
1162 param->inp_buff_y_st_addr = input_buf_y_st_addr;
1163 param->inp_buff_y_line_stride = input_buf_y_line_stride;
1164 param->inp_buff_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
1165 param->int_buff_u_st_addr = input_buf_u_st_addr;
1166 param->int_buff_v_st_addr = input_buf_v_st_addr;
1167 param->inp_buff_uv_line_stride =
1168 input_buf_uv_line_stride;
1169 param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
1170 param->out_buff_level = 0;
1171 param->out_buff_nr_y_lines = output_buf_nr_y_lines;
1172 param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET;
1173 param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET;
1174 param->out_buff_y_line_stride =
1175 output_buf_y_line_stride;
1176 param->out_buff_uv_line_stride =
1177 output_buf_uv_line_stride;
1178 param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR;
1179 param->hist_buff_line_stride =
1180 IMGU_VMEM1_HST_BUF_STRIDE;
1181 param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES;
1182 }
1183 }
1184
1185 block_stripes[0].offset = 0;
1186 if (stripes <= 1) {
1187 block_stripes[0].width = stripe_params[0].input_width;
1188 block_stripes[0].height = stripe_params[0].input_height;
1189 } else {
1190 struct imgu_fw_info *bi =
1191 &css->fwp->binary_header[css_pipe->bindex];
1192 unsigned int sp_block_width =
1193 bi->info.isp.sp.block.block_width *
1194 IPU3_UAPI_ISP_VEC_ELEMS;
1195
1196 block_stripes[0].width = roundup(stripe_params[0].input_width,
1197 sp_block_width);
1198 block_stripes[1].offset =
1199 rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
1200 stripe_params[1].input_width, sp_block_width);
1201 block_stripes[1].width =
1202 roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width -
1203 block_stripes[1].offset, sp_block_width);
1204 block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height;
1205 block_stripes[1].height = block_stripes[0].height;
1206 }
1207
1208 return 0;
1209 }
1210
1211 /*********************** Mostly 3A operations ******************************/
1212
1213 /*
1214 * This function creates a "TO-DO list" (operations) for the sp code.
1215 *
1216 * There are 2 types of operations:
1217 * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to
1218 * accelerator space (NOTE that this space is limited) associated data:
1219 * DDR address + accelerator's config set index(acc's address).
1220 *
1221 * 2. Issue "Process Lines Command" to shd accelerator
1222 * associated data: #lines + which config set to use (actually, accelerator
1223 * will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction
1224 * of not touching config sets x & (x+1)%num_of_sets when process_lines(x)
1225 * is active).
1226 *
1227 * Basically there are 2 types of operations "chunks":
1228 * 1. "initial chunk": Initially, we do as much transfers as we can (and need)
1229 * [0 - max sets(3) ] followed by 1 or 2 "process lines" operations.
1230 *
1231 * 2. "regular chunk" - 1 transfer followed by 1 process line operation.
1232 * (in some cases we might need additional transfer ate the last chunk).
1233 *
1234 * for some case:
1235 * --> init
1236 * tr (0)
1237 * tr (1)
1238 * tr (2)
1239 * pl (0)
1240 * pl (1)
1241 * --> ack (0)
1242 * tr (3)
1243 * pl (2)
1244 * --> ack (1)
1245 * pl (3)
1246 * --> ack (2)
1247 * do nothing
1248 * --> ack (3)
1249 * do nothing
1250 */
1251
1252 static int
imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data * ops,const struct ipu3_uapi_shd_grid_config * grid,unsigned int image_height)1253 imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops,
1254 const struct ipu3_uapi_shd_grid_config *grid,
1255 unsigned int image_height)
1256 {
1257 unsigned int block_height = 1 << grid->block_height_log2;
1258 unsigned int grid_height_per_slice = grid->grid_height_per_slice;
1259 unsigned int set_height = grid_height_per_slice * block_height;
1260
1261 /* We currently support only abs(y_start) > grid_height_per_slice */
1262 unsigned int positive_y_start = (unsigned int)-grid->y_start;
1263 unsigned int first_process_lines =
1264 set_height - (positive_y_start % set_height);
1265 unsigned int last_set_height;
1266 unsigned int num_of_sets;
1267
1268 struct imgu_abi_acc_operation *p_op;
1269 struct imgu_abi_acc_process_lines_cmd_data *p_pl;
1270 struct imgu_abi_shd_transfer_luts_set_data *p_tr;
1271
1272 unsigned int op_idx, pl_idx, tr_idx;
1273 unsigned char tr_set_num, pl_cfg_set;
1274
1275 /*
1276 * When the number of lines for the last process lines command
1277 * is equal to a set height, we need another line of grid cell -
1278 * additional transfer is required.
1279 */
1280 unsigned char last_tr = 0;
1281
1282 /* Add "process lines" command to the list of operations */
1283 bool add_pl;
1284 /* Add DMA xfer (config set) command to the list of ops */
1285 bool add_tr;
1286
1287 /*
1288 * Available partial grid (the part that fits into #IMGU_SHD_SETS sets)
1289 * doesn't cover whole frame - need to process in chunks
1290 */
1291 if (image_height > first_process_lines) {
1292 last_set_height =
1293 (image_height - first_process_lines) % set_height;
1294 num_of_sets = last_set_height > 0 ?
1295 (image_height - first_process_lines) / set_height + 2 :
1296 (image_height - first_process_lines) / set_height + 1;
1297 last_tr = (set_height - last_set_height <= block_height ||
1298 last_set_height == 0) ? 1 : 0;
1299 } else { /* partial grid covers whole frame */
1300 last_set_height = 0;
1301 num_of_sets = 1;
1302 first_process_lines = image_height;
1303 last_tr = set_height - image_height <= block_height ? 1 : 0;
1304 }
1305
1306 /* Init operations lists and counters */
1307 p_op = ops->operation_list;
1308 op_idx = 0;
1309 p_pl = ops->process_lines_data;
1310 pl_idx = 0;
1311 p_tr = ops->transfer_data;
1312 tr_idx = 0;
1313
1314 memset(ops, 0, sizeof(*ops));
1315
1316 /* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */
1317 tr_set_num = 0;
1318 pl_cfg_set = 0;
1319
1320 /*
1321 * Always start with a transfer - process lines command must be
1322 * initiated only after appropriate config sets are in place
1323 * (2 configuration sets per process line command, except for last one).
1324 */
1325 add_pl = false;
1326 add_tr = true;
1327
1328 while (add_pl || add_tr) {
1329 /* Transfer ops */
1330 if (add_tr) {
1331 if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
1332 tr_idx >= IMGU_ABI_SHD_MAX_TRANSFERS)
1333 return -EINVAL;
1334 p_op[op_idx].op_type =
1335 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
1336 p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE;
1337 op_idx++;
1338 p_tr[tr_idx].set_number = tr_set_num;
1339 tr_idx++;
1340 tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS;
1341 }
1342
1343 /* Process-lines ops */
1344 if (add_pl) {
1345 if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS ||
1346 pl_idx >= IMGU_ABI_SHD_MAX_PROCESS_LINES)
1347 return -EINVAL;
1348 p_op[op_idx].op_type =
1349 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1350
1351 /*
1352 * In case we have 2 process lines commands -
1353 * don't stop after the first one
1354 */
1355 if (pl_idx == 0 && num_of_sets != 1)
1356 p_op[op_idx].op_indicator =
1357 IMGU_ABI_ACC_OP_IDLE;
1358 /*
1359 * Initiate last process lines command -
1360 * end of operation list.
1361 */
1362 else if (pl_idx == num_of_sets - 1)
1363 p_op[op_idx].op_indicator =
1364 IMGU_ABI_ACC_OP_END_OF_OPS;
1365 /*
1366 * Intermediate process line command - end of operation
1367 * "chunk" (meaning few "transfers" followed by few
1368 * "process lines" commands).
1369 */
1370 else
1371 p_op[op_idx].op_indicator =
1372 IMGU_ABI_ACC_OP_END_OF_ACK;
1373
1374 op_idx++;
1375
1376 /* first process line operation */
1377 if (pl_idx == 0)
1378 p_pl[pl_idx].lines = first_process_lines;
1379 /* Last process line operation */
1380 else if (pl_idx == num_of_sets - 1 &&
1381 last_set_height > 0)
1382 p_pl[pl_idx].lines = last_set_height;
1383 else /* "regular" process lines operation */
1384 p_pl[pl_idx].lines = set_height;
1385
1386 p_pl[pl_idx].cfg_set = pl_cfg_set;
1387 pl_idx++;
1388 pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS;
1389 }
1390
1391 /*
1392 * Initially, we always transfer
1393 * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the
1394 * corresponding process lines commands.
1395 */
1396 if (tr_idx == IMGU_SHD_SETS ||
1397 tr_idx == num_of_sets + last_tr) {
1398 add_tr = false;
1399 add_pl = true;
1400 }
1401
1402 /*
1403 * We have finished the "initial" operations chunk -
1404 * be ready to get more chunks.
1405 */
1406 if (pl_idx == 2) {
1407 add_tr = true;
1408 add_pl = true;
1409 }
1410
1411 /* Stop conditions for each operation type */
1412 if (tr_idx == num_of_sets + last_tr)
1413 add_tr = false;
1414 if (pl_idx == num_of_sets)
1415 add_pl = false;
1416 }
1417
1418 return 0;
1419 }
1420
1421 /*
1422 * The follow handshake procotol is the same for AF, AWB and AWB FR.
1423 *
1424 * for n sets of meta-data, the flow is:
1425 * --> init
1426 * process-lines (0)
1427 * process-lines (1) eoc
1428 * --> ack (0)
1429 * read-meta-data (0)
1430 * process-lines (2) eoc
1431 * --> ack (1)
1432 * read-meta-data (1)
1433 * process-lines (3) eoc
1434 * ...
1435 *
1436 * --> ack (n-3)
1437 * read-meta-data (n-3)
1438 * process-lines (n-1) eoc
1439 * --> ack (n-2)
1440 * read-meta-data (n-2) eoc
1441 * --> ack (n-1)
1442 * read-meta-data (n-1) eof
1443 *
1444 * for 2 sets we get:
1445 * --> init
1446 * pl (0)
1447 * pl (1) eoc
1448 * --> ack (0)
1449 * pl (2) - rest of image, if applicable)
1450 * rmd (0) eoc
1451 * --> ack (1)
1452 * rmd (1) eof
1453 * --> (ack (2))
1454 * do nothing
1455 *
1456 * for only one set:
1457 *
1458 * --> init
1459 * pl(0) eoc
1460 * --> ack (0)
1461 * rmd (0) eof
1462 *
1463 * grid smaller than image case
1464 * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
1465 * start at (0,0)
1466 * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
1467 * => 1st process lines = 80
1468 * we're left with 128-80=48 lines (6 blocks vertical)
1469 * => 2nd process lines = 48
1470 * last process lines to cover the image - image_height - 128
1471 *
1472 * --> init
1473 * pl (0) first
1474 * pl (1) last-in-grid
1475 * --> ack (0)
1476 * rmd (0)
1477 * pl (2) after-grid
1478 * --> ack (1)
1479 * rmd (1) eof
1480 * --> ack (2)
1481 * do nothing
1482 */
1483 struct process_lines {
1484 unsigned int image_height;
1485 unsigned short grid_height;
1486 unsigned short block_height;
1487 unsigned short y_start;
1488 unsigned char grid_height_per_slice;
1489
1490 unsigned short max_op; /* max operation */
1491 unsigned short max_tr; /* max transaction */
1492 unsigned char acc_enable;
1493 };
1494
1495 /* Helper to config intra_frame_operations_data. */
1496 static int
imgu_css_acc_process_lines(const struct process_lines * pl,struct imgu_abi_acc_operation * p_op,struct imgu_abi_acc_process_lines_cmd_data * p_pl,struct imgu_abi_acc_transfer_op_data * p_tr)1497 imgu_css_acc_process_lines(const struct process_lines *pl,
1498 struct imgu_abi_acc_operation *p_op,
1499 struct imgu_abi_acc_process_lines_cmd_data *p_pl,
1500 struct imgu_abi_acc_transfer_op_data *p_tr)
1501 {
1502 unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0;
1503 unsigned char tr_set_num = 0, pl_cfg_set = 0;
1504 const unsigned short grid_last_line =
1505 pl->y_start + pl->grid_height * pl->block_height;
1506 const unsigned short process_lines =
1507 pl->grid_height_per_slice * pl->block_height;
1508
1509 unsigned int process_lines_after_grid;
1510 unsigned short first_process_lines;
1511 unsigned short last_process_lines_in_grid;
1512
1513 unsigned short num_of_process_lines;
1514 unsigned short num_of_sets;
1515
1516 if (pl->grid_height_per_slice == 0)
1517 return -EINVAL;
1518
1519 if (pl->acc_enable && grid_last_line > pl->image_height)
1520 return -EINVAL;
1521
1522 num_of_sets = pl->grid_height / pl->grid_height_per_slice;
1523 if (num_of_sets * pl->grid_height_per_slice < pl->grid_height)
1524 num_of_sets++;
1525
1526 /* Account for two line delay inside the FF */
1527 if (pl->max_op == IMGU_ABI_AF_MAX_OPERATIONS) {
1528 first_process_lines = process_lines + pl->y_start + 2;
1529 last_process_lines_in_grid =
1530 (grid_last_line - first_process_lines) -
1531 ((num_of_sets - 2) * process_lines) + 4;
1532 process_lines_after_grid =
1533 pl->image_height - grid_last_line - 4;
1534 } else {
1535 first_process_lines = process_lines + pl->y_start;
1536 last_process_lines_in_grid =
1537 (grid_last_line - first_process_lines) -
1538 ((num_of_sets - 2) * process_lines);
1539 process_lines_after_grid = pl->image_height - grid_last_line;
1540 }
1541
1542 num_of_process_lines = num_of_sets;
1543 if (process_lines_after_grid > 0)
1544 num_of_process_lines++;
1545
1546 while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) {
1547 /* Read meta-data */
1548 if (pl_idx >= 2 || (pl_idx == 1 && num_of_sets == 1)) {
1549 if (op_idx >= pl->max_op || tr_idx >= pl->max_tr)
1550 return -EINVAL;
1551
1552 p_op[op_idx].op_type =
1553 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
1554
1555 if (tr_idx == num_of_sets - 1)
1556 /* The last operation is always a tr */
1557 p_op[op_idx].op_indicator =
1558 IMGU_ABI_ACC_OP_END_OF_OPS;
1559 else if (tr_idx == num_of_sets - 2)
1560 if (process_lines_after_grid == 0)
1561 /*
1562 * No additional pl op left -
1563 * this op is left as lats of cycle
1564 */
1565 p_op[op_idx].op_indicator =
1566 IMGU_ABI_ACC_OP_END_OF_ACK;
1567 else
1568 /*
1569 * We still have to process-lines after
1570 * the grid so have one more pl op
1571 */
1572 p_op[op_idx].op_indicator =
1573 IMGU_ABI_ACC_OP_IDLE;
1574 else
1575 /* Default - usually there's a pl after a tr */
1576 p_op[op_idx].op_indicator =
1577 IMGU_ABI_ACC_OP_IDLE;
1578
1579 op_idx++;
1580 if (p_tr) {
1581 p_tr[tr_idx].set_number = tr_set_num;
1582 tr_set_num = 1 - tr_set_num;
1583 }
1584 tr_idx++;
1585 }
1586
1587 /* process_lines */
1588 if (pl_idx < num_of_process_lines) {
1589 if (op_idx >= pl->max_op || pl_idx >= pl->max_tr)
1590 return -EINVAL;
1591
1592 p_op[op_idx].op_type =
1593 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1594 if (pl_idx == 0)
1595 if (num_of_process_lines == 1)
1596 /* Only one pl op */
1597 p_op[op_idx].op_indicator =
1598 IMGU_ABI_ACC_OP_END_OF_ACK;
1599 else
1600 /* On init - do two pl ops */
1601 p_op[op_idx].op_indicator =
1602 IMGU_ABI_ACC_OP_IDLE;
1603 else
1604 /* Usually pl is the end of the ack cycle */
1605 p_op[op_idx].op_indicator =
1606 IMGU_ABI_ACC_OP_END_OF_ACK;
1607
1608 op_idx++;
1609
1610 if (pl_idx == 0)
1611 /* First process line */
1612 p_pl[pl_idx].lines = first_process_lines;
1613 else if (pl_idx == num_of_sets - 1)
1614 /* Last in grid */
1615 p_pl[pl_idx].lines = last_process_lines_in_grid;
1616 else if (pl_idx == num_of_process_lines - 1)
1617 /* After the grid */
1618 p_pl[pl_idx].lines = process_lines_after_grid;
1619 else
1620 /* Inside the grid */
1621 p_pl[pl_idx].lines = process_lines;
1622
1623 if (p_tr) {
1624 p_pl[pl_idx].cfg_set = pl_cfg_set;
1625 pl_cfg_set = 1 - pl_cfg_set;
1626 }
1627 pl_idx++;
1628 }
1629 }
1630
1631 return 0;
1632 }
1633
imgu_css_af_ops_calc(struct imgu_css * css,unsigned int pipe,struct imgu_abi_af_config * af_config)1634 static int imgu_css_af_ops_calc(struct imgu_css *css, unsigned int pipe,
1635 struct imgu_abi_af_config *af_config)
1636 {
1637 struct imgu_abi_af_intra_frame_operations_data *to =
1638 &af_config->operations_data;
1639 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1640 struct imgu_fw_info *bi =
1641 &css->fwp->binary_header[css_pipe->bindex];
1642
1643 struct process_lines pl = {
1644 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1645 .grid_height = af_config->config.grid_cfg.height,
1646 .block_height =
1647 1 << af_config->config.grid_cfg.block_height_log2,
1648 .y_start = af_config->config.grid_cfg.y_start &
1649 IPU3_UAPI_GRID_START_MASK,
1650 .grid_height_per_slice =
1651 af_config->stripes[0].grid_cfg.height_per_slice,
1652 .max_op = IMGU_ABI_AF_MAX_OPERATIONS,
1653 .max_tr = IMGU_ABI_AF_MAX_TRANSFERS,
1654 .acc_enable = bi->info.isp.sp.enable.af,
1655 };
1656
1657 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1658 NULL);
1659 }
1660
1661 static int
imgu_css_awb_fr_ops_calc(struct imgu_css * css,unsigned int pipe,struct imgu_abi_awb_fr_config * awb_fr_config)1662 imgu_css_awb_fr_ops_calc(struct imgu_css *css, unsigned int pipe,
1663 struct imgu_abi_awb_fr_config *awb_fr_config)
1664 {
1665 struct imgu_abi_awb_fr_intra_frame_operations_data *to =
1666 &awb_fr_config->operations_data;
1667 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1668 struct imgu_fw_info *bi =
1669 &css->fwp->binary_header[css_pipe->bindex];
1670 struct process_lines pl = {
1671 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1672 .grid_height = awb_fr_config->config.grid_cfg.height,
1673 .block_height =
1674 1 << awb_fr_config->config.grid_cfg.block_height_log2,
1675 .y_start = awb_fr_config->config.grid_cfg.y_start &
1676 IPU3_UAPI_GRID_START_MASK,
1677 .grid_height_per_slice =
1678 awb_fr_config->stripes[0].grid_cfg.height_per_slice,
1679 .max_op = IMGU_ABI_AWB_FR_MAX_OPERATIONS,
1680 .max_tr = IMGU_ABI_AWB_FR_MAX_PROCESS_LINES,
1681 .acc_enable = bi->info.isp.sp.enable.awb_fr_acc,
1682 };
1683
1684 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1685 NULL);
1686 }
1687
imgu_css_awb_ops_calc(struct imgu_css * css,unsigned int pipe,struct imgu_abi_awb_config * awb_config)1688 static int imgu_css_awb_ops_calc(struct imgu_css *css, unsigned int pipe,
1689 struct imgu_abi_awb_config *awb_config)
1690 {
1691 struct imgu_abi_awb_intra_frame_operations_data *to =
1692 &awb_config->operations_data;
1693 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1694 struct imgu_fw_info *bi =
1695 &css->fwp->binary_header[css_pipe->bindex];
1696
1697 struct process_lines pl = {
1698 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height,
1699 .grid_height = awb_config->config.grid.height,
1700 .block_height =
1701 1 << awb_config->config.grid.block_height_log2,
1702 .y_start = awb_config->config.grid.y_start,
1703 .grid_height_per_slice =
1704 awb_config->stripes[0].grid.height_per_slice,
1705 .max_op = IMGU_ABI_AWB_MAX_OPERATIONS,
1706 .max_tr = IMGU_ABI_AWB_MAX_TRANSFERS,
1707 .acc_enable = bi->info.isp.sp.enable.awb_acc,
1708 };
1709
1710 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data,
1711 to->transfer_data);
1712 }
1713
imgu_css_grid_end(u16 start,u8 width,u8 block_width_log2)1714 static u16 imgu_css_grid_end(u16 start, u8 width, u8 block_width_log2)
1715 {
1716 return (start & IPU3_UAPI_GRID_START_MASK) +
1717 (width << block_width_log2) - 1;
1718 }
1719
imgu_css_grid_end_calc(struct ipu3_uapi_grid_config * grid_cfg)1720 static void imgu_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg)
1721 {
1722 grid_cfg->x_end = imgu_css_grid_end(grid_cfg->x_start, grid_cfg->width,
1723 grid_cfg->block_width_log2);
1724 grid_cfg->y_end = imgu_css_grid_end(grid_cfg->y_start, grid_cfg->height,
1725 grid_cfg->block_height_log2);
1726 }
1727
1728 /****************** config computation *****************************/
1729
imgu_css_cfg_acc_stripe(struct imgu_css * css,unsigned int pipe,struct imgu_abi_acc_param * acc)1730 static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe,
1731 struct imgu_abi_acc_param *acc)
1732 {
1733 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1734 const struct imgu_fw_info *bi =
1735 &css->fwp->binary_header[css_pipe->bindex];
1736 struct imgu_css_scaler_info scaler_luma, scaler_chroma;
1737 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
1738 const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2;
1739 unsigned int bds_ds, i;
1740
1741 memset(acc, 0, sizeof(*acc));
1742
1743 /* acc_param: osys_config */
1744
1745 if (imgu_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma,
1746 &scaler_chroma, acc->stripe.block_stripes))
1747 return -EINVAL;
1748
1749 /* acc_param: stripe data */
1750
1751 /*
1752 * For the striped case the approach is as follows:
1753 * 1. down-scaled stripes are calculated - with 128 overlap
1754 * (this is the main limiter therefore it's first)
1755 * 2. input stripes are derived by up-scaling the down-scaled stripes
1756 * (there are no alignment requirements on input stripes)
1757 * 3. output stripes are derived from down-scaled stripes too
1758 */
1759
1760 acc->stripe.num_of_stripes = stripes;
1761 acc->stripe.input_frame.width =
1762 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
1763 acc->stripe.input_frame.height =
1764 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
1765 acc->stripe.input_frame.bayer_order =
1766 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
1767
1768 for (i = 0; i < stripes; i++)
1769 acc->stripe.bds_out_stripes[i].height =
1770 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1771 acc->stripe.bds_out_stripes[0].offset = 0;
1772 if (stripes <= 1) {
1773 acc->stripe.bds_out_stripes[0].width =
1774 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
1775 } else {
1776 /* Image processing is divided into two stripes */
1777 acc->stripe.bds_out_stripes[0].width =
1778 acc->stripe.bds_out_stripes[1].width =
1779 (css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f;
1780 /*
1781 * Sum of width of the two stripes should not be smaller
1782 * than output width and must be even times of overlapping
1783 * unit f.
1784 */
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 if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) &&
1789 (css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) {
1790 acc->stripe.bds_out_stripes[0].width += f;
1791 acc->stripe.bds_out_stripes[1].width += f;
1792 }
1793 /* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
1794 acc->stripe.bds_out_stripes[1].offset =
1795 acc->stripe.bds_out_stripes[0].width - 2 * f;
1796 }
1797
1798 acc->stripe.effective_stripes[0].height =
1799 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
1800 acc->stripe.effective_stripes[0].offset = 0;
1801 acc->stripe.bds_out_stripes_no_overlap[0].height =
1802 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1803 acc->stripe.bds_out_stripes_no_overlap[0].offset = 0;
1804 acc->stripe.output_stripes[0].height =
1805 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1806 acc->stripe.output_stripes[0].offset = 0;
1807 if (stripes <= 1) {
1808 acc->stripe.down_scaled_stripes[0].width =
1809 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1810 acc->stripe.down_scaled_stripes[0].height =
1811 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1812 acc->stripe.down_scaled_stripes[0].offset = 0;
1813
1814 acc->stripe.effective_stripes[0].width =
1815 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
1816 acc->stripe.bds_out_stripes_no_overlap[0].width =
1817 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f);
1818
1819 acc->stripe.output_stripes[0].width =
1820 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
1821 } else { /* Two stripes */
1822 bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width *
1823 IMGU_BDS_GRANULARITY /
1824 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1825
1826 acc->stripe.down_scaled_stripes[0] =
1827 acc->stripe.bds_out_stripes[0];
1828 acc->stripe.down_scaled_stripes[1] =
1829 acc->stripe.bds_out_stripes[1];
1830 if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f))
1831 acc->stripe.down_scaled_stripes[1].width +=
1832 (css_pipe->rect[IPU3_CSS_RECT_BDS].width
1833 & (f - 1)) - f;
1834
1835 acc->stripe.effective_stripes[0].width = bds_ds *
1836 acc->stripe.down_scaled_stripes[0].width /
1837 IMGU_BDS_GRANULARITY;
1838 acc->stripe.effective_stripes[1].width = bds_ds *
1839 acc->stripe.down_scaled_stripes[1].width /
1840 IMGU_BDS_GRANULARITY;
1841 acc->stripe.effective_stripes[1].height =
1842 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
1843 acc->stripe.effective_stripes[1].offset = bds_ds *
1844 acc->stripe.down_scaled_stripes[1].offset /
1845 IMGU_BDS_GRANULARITY;
1846
1847 acc->stripe.bds_out_stripes_no_overlap[0].width =
1848 acc->stripe.bds_out_stripes_no_overlap[1].offset =
1849 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2;
1850 acc->stripe.bds_out_stripes_no_overlap[1].width =
1851 DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)
1852 / 2 * f;
1853 acc->stripe.bds_out_stripes_no_overlap[1].height =
1854 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1855
1856 acc->stripe.output_stripes[0].width =
1857 acc->stripe.down_scaled_stripes[0].width - f;
1858 acc->stripe.output_stripes[1].width =
1859 acc->stripe.down_scaled_stripes[1].width - f;
1860 acc->stripe.output_stripes[1].height =
1861 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1862 acc->stripe.output_stripes[1].offset =
1863 acc->stripe.output_stripes[0].width;
1864 }
1865
1866 acc->stripe.output_system_in_frame_width =
1867 css_pipe->rect[IPU3_CSS_RECT_GDC].width;
1868 acc->stripe.output_system_in_frame_height =
1869 css_pipe->rect[IPU3_CSS_RECT_GDC].height;
1870
1871 acc->stripe.effective_frame_width =
1872 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width;
1873 acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width;
1874 acc->stripe.out_frame_width =
1875 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
1876 acc->stripe.out_frame_height =
1877 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
1878 acc->stripe.gdc_in_buffer_width =
1879 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
1880 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
1881 acc->stripe.gdc_in_buffer_height =
1882 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
1883 acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X;
1884 acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y;
1885 acc->stripe.display_frame_width =
1886 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
1887 acc->stripe.display_frame_height =
1888 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
1889 acc->stripe.bds_aligned_frame_width =
1890 roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width,
1891 2 * IPU3_UAPI_ISP_VEC_ELEMS);
1892
1893 if (stripes > 1)
1894 acc->stripe.half_overlap_vectors =
1895 IMGU_STRIPE_FIXED_HALF_OVERLAP;
1896 else
1897 acc->stripe.half_overlap_vectors = 0;
1898
1899 return 0;
1900 }
1901
imgu_css_cfg_acc_dvs(struct imgu_css * css,struct imgu_abi_acc_param * acc,unsigned int pipe)1902 static void imgu_css_cfg_acc_dvs(struct imgu_css *css,
1903 struct imgu_abi_acc_param *acc,
1904 unsigned int pipe)
1905 {
1906 unsigned int i;
1907 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1908
1909 /* Disable DVS statistics */
1910 acc->dvs_stat.operations_data.process_lines_data[0].lines =
1911 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1912 acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0;
1913 acc->dvs_stat.operations_data.ops[0].op_type =
1914 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
1915 acc->dvs_stat.operations_data.ops[0].op_indicator =
1916 IMGU_ABI_ACC_OP_NO_OPS;
1917 for (i = 0; i < IMGU_ABI_DVS_STAT_LEVELS; i++)
1918 acc->dvs_stat.cfg.grd_config[i].enable = 0;
1919 }
1920
acc_bds_per_stripe_data(struct imgu_css * css,struct imgu_abi_acc_param * acc,const int i,unsigned int pipe)1921 static void acc_bds_per_stripe_data(struct imgu_css *css,
1922 struct imgu_abi_acc_param *acc,
1923 const int i, unsigned int pipe)
1924 {
1925 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1926
1927 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0;
1928 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0;
1929 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0;
1930 acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 =
1931 acc->bds.hor.hor_ctrl0;
1932 acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width =
1933 acc->stripe.down_scaled_stripes[i].width;
1934 acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width =
1935 acc->stripe.down_scaled_stripes[i].width;
1936 acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height =
1937 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
1938 }
1939
1940 /*
1941 * Configure `acc' parameters. `acc_old' contains the old values (or is NULL)
1942 * and `acc_user' contains new prospective values. `use' contains flags
1943 * telling which fields to take from the old values (or generate if it is NULL)
1944 * and which to take from the new user values.
1945 */
imgu_css_cfg_acc(struct imgu_css * css,unsigned int pipe,struct ipu3_uapi_flags * use,struct imgu_abi_acc_param * acc,struct imgu_abi_acc_param * acc_old,struct ipu3_uapi_acc_param * acc_user)1946 int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe,
1947 struct ipu3_uapi_flags *use,
1948 struct imgu_abi_acc_param *acc,
1949 struct imgu_abi_acc_param *acc_old,
1950 struct ipu3_uapi_acc_param *acc_user)
1951 {
1952 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
1953 const struct imgu_fw_info *bi =
1954 &css->fwp->binary_header[css_pipe->bindex];
1955 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
1956 const unsigned int tnr_frame_width =
1957 acc->stripe.bds_aligned_frame_width;
1958 const unsigned int min_overlap = 10;
1959 const struct v4l2_pix_format_mplane *pixm =
1960 &css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
1961 const struct imgu_css_bds_config *cfg_bds;
1962 struct imgu_abi_input_feeder_data *feeder_data;
1963
1964 unsigned int bds_ds, ofs_x, ofs_y, i, width, height;
1965 u8 b_w_log2; /* Block width log2 */
1966
1967 /* Update stripe using chroma and luma */
1968
1969 if (imgu_css_cfg_acc_stripe(css, pipe, acc))
1970 return -EINVAL;
1971
1972 /* acc_param: input_feeder_config */
1973
1974 ofs_x = ((pixm->width -
1975 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
1976 ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1977 IMGU_ABI_BAYER_ORDER_RGGB ||
1978 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1979 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
1980 ofs_y = ((pixm->height -
1981 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
1982 ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1983 IMGU_ABI_BAYER_ORDER_BGGR ||
1984 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
1985 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
1986 acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline;
1987 acc->input_feeder.data.start_row_address =
1988 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
1989 ofs_y * acc->input_feeder.data.row_stride;
1990 acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
1991
1992 acc->input_feeder.data_per_stripe.input_feeder_data[0].data =
1993 acc->input_feeder.data;
1994
1995 ofs_x += acc->stripe.effective_stripes[1].offset;
1996
1997 feeder_data =
1998 &acc->input_feeder.data_per_stripe.input_feeder_data[1].data;
1999 feeder_data->row_stride = acc->input_feeder.data.row_stride;
2000 feeder_data->start_row_address =
2001 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
2002 ofs_y * acc->input_feeder.data.row_stride;
2003 feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
2004
2005 /* acc_param: bnr_static_config */
2006
2007 /*
2008 * Originate from user or be the original default values if user has
2009 * never set them before, when user gives a new set of parameters,
2010 * for each chunk in the parameter structure there is a flag use->xxx
2011 * whether to use the user-provided parameter or not. If not, the
2012 * parameter remains unchanged in the driver:
2013 * it's value is taken from acc_old.
2014 */
2015 if (use && use->acc_bnr) {
2016 /* Take values from user */
2017 acc->bnr = acc_user->bnr;
2018 } else if (acc_old) {
2019 /* Use old value */
2020 acc->bnr = acc_old->bnr;
2021 } else {
2022 /* Calculate from scratch */
2023 acc->bnr = imgu_css_bnr_defaults;
2024 }
2025
2026 acc->bnr.column_size = tnr_frame_width;
2027
2028 /* acc_param: bnr_static_config_green_disparity */
2029
2030 if (use && use->acc_green_disparity) {
2031 /* Take values from user */
2032 acc->green_disparity = acc_user->green_disparity;
2033 } else if (acc_old) {
2034 /* Use old value */
2035 acc->green_disparity = acc_old->green_disparity;
2036 } else {
2037 /* Calculate from scratch */
2038 memset(&acc->green_disparity, 0, sizeof(acc->green_disparity));
2039 }
2040
2041 /* acc_param: dm_config */
2042
2043 if (use && use->acc_dm) {
2044 /* Take values from user */
2045 acc->dm = acc_user->dm;
2046 } else if (acc_old) {
2047 /* Use old value */
2048 acc->dm = acc_old->dm;
2049 } else {
2050 /* Calculate from scratch */
2051 acc->dm = imgu_css_dm_defaults;
2052 }
2053
2054 acc->dm.frame_width = tnr_frame_width;
2055
2056 /* acc_param: ccm_mat_config */
2057
2058 if (use && use->acc_ccm) {
2059 /* Take values from user */
2060 acc->ccm = acc_user->ccm;
2061 } else if (acc_old) {
2062 /* Use old value */
2063 acc->ccm = acc_old->ccm;
2064 } else {
2065 /* Calculate from scratch */
2066 acc->ccm = imgu_css_ccm_defaults;
2067 }
2068
2069 /* acc_param: gamma_config */
2070
2071 if (use && use->acc_gamma) {
2072 /* Take values from user */
2073 acc->gamma = acc_user->gamma;
2074 } else if (acc_old) {
2075 /* Use old value */
2076 acc->gamma = acc_old->gamma;
2077 } else {
2078 /* Calculate from scratch */
2079 acc->gamma.gc_ctrl.enable = 1;
2080 acc->gamma.gc_lut = imgu_css_gamma_lut;
2081 }
2082
2083 /* acc_param: csc_mat_config */
2084
2085 if (use && use->acc_csc) {
2086 /* Take values from user */
2087 acc->csc = acc_user->csc;
2088 } else if (acc_old) {
2089 /* Use old value */
2090 acc->csc = acc_old->csc;
2091 } else {
2092 /* Calculate from scratch */
2093 acc->csc = imgu_css_csc_defaults;
2094 }
2095
2096 /* acc_param: cds_params */
2097
2098 if (use && use->acc_cds) {
2099 /* Take values from user */
2100 acc->cds = acc_user->cds;
2101 } else if (acc_old) {
2102 /* Use old value */
2103 acc->cds = acc_old->cds;
2104 } else {
2105 /* Calculate from scratch */
2106 acc->cds = imgu_css_cds_defaults;
2107 }
2108
2109 /* acc_param: shd_config */
2110
2111 if (use && use->acc_shd) {
2112 /* Take values from user */
2113 acc->shd.shd = acc_user->shd.shd;
2114 acc->shd.shd_lut = acc_user->shd.shd_lut;
2115 } else if (acc_old) {
2116 /* Use old value */
2117 acc->shd.shd = acc_old->shd.shd;
2118 acc->shd.shd_lut = acc_old->shd.shd_lut;
2119 } else {
2120 /* Calculate from scratch */
2121 acc->shd.shd = imgu_css_shd_defaults;
2122 memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut));
2123 }
2124
2125 if (acc->shd.shd.grid.width <= 0)
2126 return -EINVAL;
2127
2128 acc->shd.shd.grid.grid_height_per_slice =
2129 IMGU_ABI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width;
2130
2131 if (acc->shd.shd.grid.grid_height_per_slice <= 0)
2132 return -EINVAL;
2133
2134 acc->shd.shd.general.init_set_vrt_offst_ul =
2135 (-acc->shd.shd.grid.y_start >>
2136 acc->shd.shd.grid.block_height_log2) %
2137 acc->shd.shd.grid.grid_height_per_slice;
2138
2139 if (imgu_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid,
2140 css_pipe->rect[IPU3_CSS_RECT_BDS].height))
2141 return -EINVAL;
2142
2143 /* acc_param: dvs_stat_config */
2144 imgu_css_cfg_acc_dvs(css, acc, pipe);
2145
2146 /* acc_param: yuvp1_iefd_config */
2147
2148 if (use && use->acc_iefd) {
2149 /* Take values from user */
2150 acc->iefd = acc_user->iefd;
2151 } else if (acc_old) {
2152 /* Use old value */
2153 acc->iefd = acc_old->iefd;
2154 } else {
2155 /* Calculate from scratch */
2156 acc->iefd = imgu_css_iefd_defaults;
2157 }
2158
2159 /* acc_param: yuvp1_yds_config yds_c0 */
2160
2161 if (use && use->acc_yds_c0) {
2162 /* Take values from user */
2163 acc->yds_c0 = acc_user->yds_c0;
2164 } else if (acc_old) {
2165 /* Use old value */
2166 acc->yds_c0 = acc_old->yds_c0;
2167 } else {
2168 /* Calculate from scratch */
2169 acc->yds_c0 = imgu_css_yds_defaults;
2170 }
2171
2172 /* acc_param: yuvp1_chnr_config chnr_c0 */
2173
2174 if (use && use->acc_chnr_c0) {
2175 /* Take values from user */
2176 acc->chnr_c0 = acc_user->chnr_c0;
2177 } else if (acc_old) {
2178 /* Use old value */
2179 acc->chnr_c0 = acc_old->chnr_c0;
2180 } else {
2181 /* Calculate from scratch */
2182 acc->chnr_c0 = imgu_css_chnr_defaults;
2183 }
2184
2185 /* acc_param: yuvp1_y_ee_nr_config */
2186
2187 if (use && use->acc_y_ee_nr) {
2188 /* Take values from user */
2189 acc->y_ee_nr = acc_user->y_ee_nr;
2190 } else if (acc_old) {
2191 /* Use old value */
2192 acc->y_ee_nr = acc_old->y_ee_nr;
2193 } else {
2194 /* Calculate from scratch */
2195 acc->y_ee_nr = imgu_css_y_ee_nr_defaults;
2196 }
2197
2198 /* acc_param: yuvp1_yds_config yds */
2199
2200 if (use && use->acc_yds) {
2201 /* Take values from user */
2202 acc->yds = acc_user->yds;
2203 } else if (acc_old) {
2204 /* Use old value */
2205 acc->yds = acc_old->yds;
2206 } else {
2207 /* Calculate from scratch */
2208 acc->yds = imgu_css_yds_defaults;
2209 }
2210
2211 /* acc_param: yuvp1_chnr_config chnr */
2212
2213 if (use && use->acc_chnr) {
2214 /* Take values from user */
2215 acc->chnr = acc_user->chnr;
2216 } else if (acc_old) {
2217 /* Use old value */
2218 acc->chnr = acc_old->chnr;
2219 } else {
2220 /* Calculate from scratch */
2221 acc->chnr = imgu_css_chnr_defaults;
2222 }
2223
2224 /* acc_param: yuvp2_y_tm_lut_static_config */
2225
2226 for (i = 0; i < IMGU_ABI_YUVP2_YTM_LUT_ENTRIES; i++)
2227 acc->ytm.entries[i] = i * 32;
2228 acc->ytm.enable = 0; /* Always disabled on IPU3 */
2229
2230 /* acc_param: yuvp1_yds_config yds2 */
2231
2232 if (use && use->acc_yds2) {
2233 /* Take values from user */
2234 acc->yds2 = acc_user->yds2;
2235 } else if (acc_old) {
2236 /* Use old value */
2237 acc->yds2 = acc_old->yds2;
2238 } else {
2239 /* Calculate from scratch */
2240 acc->yds2 = imgu_css_yds_defaults;
2241 }
2242
2243 /* acc_param: yuvp2_tcc_static_config */
2244
2245 if (use && use->acc_tcc) {
2246 /* Take values from user */
2247 acc->tcc = acc_user->tcc;
2248 } else if (acc_old) {
2249 /* Use old value */
2250 acc->tcc = acc_old->tcc;
2251 } else {
2252 /* Calculate from scratch */
2253 memset(&acc->tcc, 0, sizeof(acc->tcc));
2254
2255 acc->tcc.gen_control.en = 1;
2256 acc->tcc.gen_control.blend_shift = 3;
2257 acc->tcc.gen_control.gain_according_to_y_only = 1;
2258 acc->tcc.gen_control.gamma = 8;
2259 acc->tcc.gen_control.delta = 0;
2260
2261 for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) {
2262 acc->tcc.macc_table.entries[i].a = 1024;
2263 acc->tcc.macc_table.entries[i].b = 0;
2264 acc->tcc.macc_table.entries[i].c = 0;
2265 acc->tcc.macc_table.entries[i].d = 1024;
2266 }
2267
2268 acc->tcc.inv_y_lut.entries[6] = 1023;
2269 for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++)
2270 acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6);
2271
2272 acc->tcc.gain_pcwl = imgu_css_tcc_gain_pcwl_lut;
2273 acc->tcc.r_sqr_lut = imgu_css_tcc_r_sqr_lut;
2274 }
2275
2276 /* acc_param: dpc_config */
2277
2278 if (use && use->acc_dpc)
2279 return -EINVAL; /* Not supported yet */
2280
2281 /* Just disable by default */
2282 memset(&acc->dpc, 0, sizeof(acc->dpc));
2283
2284 /* acc_param: bds_config */
2285
2286 bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height *
2287 IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2288 if (bds_ds < IMGU_BDS_MIN_SF_INV ||
2289 bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(imgu_css_bds_configs))
2290 return -EINVAL;
2291
2292 cfg_bds = &imgu_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV];
2293 acc->bds.hor.hor_ctrl1.hor_crop_en = 0;
2294 acc->bds.hor.hor_ctrl1.hor_crop_start = 0;
2295 acc->bds.hor.hor_ctrl1.hor_crop_end = 0;
2296 acc->bds.hor.hor_ctrl0.sample_patrn_length =
2297 cfg_bds->sample_patrn_length;
2298 acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en;
2299 acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
2300 acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
2301 acc->bds.hor.hor_ctrl0.out_frame_width =
2302 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
2303 acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr;
2304 acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr;
2305 acc->bds.hor.hor_ctrl2.input_frame_height =
2306 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height;
2307 acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
2308 acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
2309 acc->bds.ver.ver_ctrl0.sample_patrn_length =
2310 cfg_bds->sample_patrn_length;
2311 acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en;
2312 acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr;
2313 acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr;
2314 acc->bds.ver.ver_ctrl1.out_frame_width =
2315 css_pipe->rect[IPU3_CSS_RECT_BDS].width;
2316 acc->bds.ver.ver_ctrl1.out_frame_height =
2317 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2318 for (i = 0; i < stripes; i++)
2319 acc_bds_per_stripe_data(css, acc, i, pipe);
2320
2321 acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en;
2322
2323 /* acc_param: anr_config */
2324
2325 if (use && use->acc_anr) {
2326 /* Take values from user */
2327 acc->anr.transform = acc_user->anr.transform;
2328 acc->anr.stitch.anr_stitch_en =
2329 acc_user->anr.stitch.anr_stitch_en;
2330 memcpy(acc->anr.stitch.pyramid, acc_user->anr.stitch.pyramid,
2331 sizeof(acc->anr.stitch.pyramid));
2332 } else if (acc_old) {
2333 /* Use old value */
2334 acc->anr.transform = acc_old->anr.transform;
2335 acc->anr.stitch.anr_stitch_en =
2336 acc_old->anr.stitch.anr_stitch_en;
2337 memcpy(acc->anr.stitch.pyramid, acc_old->anr.stitch.pyramid,
2338 sizeof(acc->anr.stitch.pyramid));
2339 } else {
2340 /* Calculate from scratch */
2341 acc->anr = imgu_css_anr_defaults;
2342 }
2343
2344 /* Always enabled */
2345 acc->anr.search.enable = 1;
2346 acc->anr.transform.enable = 1;
2347 acc->anr.tile2strm.enable = 1;
2348 acc->anr.tile2strm.frame_width =
2349 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2350 acc->anr.search.frame_width = acc->anr.tile2strm.frame_width;
2351 acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width;
2352 acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2353 acc->anr.search.frame_height = acc->anr.tile2strm.frame_height;
2354 acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height;
2355
2356 width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2357 height = css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2358
2359 if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET)
2360 acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width;
2361 if (acc->anr.transform.xreset < IPU3_UAPI_ANR_MIN_RESET)
2362 acc->anr.transform.xreset = IPU3_UAPI_ANR_MIN_RESET;
2363
2364 if (acc->anr.transform.yreset + height > IPU3_UAPI_ANR_MAX_RESET)
2365 acc->anr.transform.yreset = IPU3_UAPI_ANR_MAX_RESET - height;
2366 if (acc->anr.transform.yreset < IPU3_UAPI_ANR_MIN_RESET)
2367 acc->anr.transform.yreset = IPU3_UAPI_ANR_MIN_RESET;
2368
2369 /* acc_param: awb_fr_config */
2370
2371 if (use && use->acc_awb_fr) {
2372 /* Take values from user */
2373 acc->awb_fr.config = acc_user->awb_fr;
2374 } else if (acc_old) {
2375 /* Use old value */
2376 acc->awb_fr.config = acc_old->awb_fr.config;
2377 } else {
2378 /* Set from scratch */
2379 acc->awb_fr.config = imgu_css_awb_fr_defaults;
2380 }
2381
2382 imgu_css_grid_end_calc(&acc->awb_fr.config.grid_cfg);
2383
2384 if (acc->awb_fr.config.grid_cfg.width <= 0)
2385 return -EINVAL;
2386
2387 acc->awb_fr.config.grid_cfg.height_per_slice =
2388 IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET /
2389 acc->awb_fr.config.grid_cfg.width;
2390
2391 for (i = 0; i < stripes; i++)
2392 acc->awb_fr.stripes[i] = acc->awb_fr.config;
2393
2394 if (acc->awb_fr.config.grid_cfg.x_start >=
2395 acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2396 /* Enable only for rightmost stripe, disable left */
2397 acc->awb_fr.stripes[0].grid_cfg.y_start &=
2398 ~IPU3_UAPI_GRID_Y_START_EN;
2399 } else if (acc->awb_fr.config.grid_cfg.x_end <=
2400 acc->stripe.bds_out_stripes[0].width - min_overlap) {
2401 /* Enable only for leftmost stripe, disable right */
2402 acc->awb_fr.stripes[1].grid_cfg.y_start &=
2403 ~IPU3_UAPI_GRID_Y_START_EN;
2404 } else {
2405 /* Enable for both stripes */
2406 u16 end; /* width for grid end */
2407
2408 acc->awb_fr.stripes[0].grid_cfg.width =
2409 (acc->stripe.bds_out_stripes[0].width - min_overlap -
2410 acc->awb_fr.config.grid_cfg.x_start + 1) >>
2411 acc->awb_fr.config.grid_cfg.block_width_log2;
2412 acc->awb_fr.stripes[1].grid_cfg.width =
2413 acc->awb_fr.config.grid_cfg.width -
2414 acc->awb_fr.stripes[0].grid_cfg.width;
2415
2416 b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2;
2417 end = imgu_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start,
2418 acc->awb_fr.stripes[0].grid_cfg.width,
2419 b_w_log2);
2420 acc->awb_fr.stripes[0].grid_cfg.x_end = end;
2421
2422 acc->awb_fr.stripes[1].grid_cfg.x_start =
2423 (acc->awb_fr.stripes[0].grid_cfg.x_end + 1 -
2424 acc->stripe.down_scaled_stripes[1].offset) &
2425 IPU3_UAPI_GRID_START_MASK;
2426 b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2;
2427 end = imgu_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start,
2428 acc->awb_fr.stripes[1].grid_cfg.width,
2429 b_w_log2);
2430 acc->awb_fr.stripes[1].grid_cfg.x_end = end;
2431
2432 /*
2433 * To reduce complexity of debubbling and loading
2434 * statistics fix grid_height_per_slice to 1 for both
2435 * stripes.
2436 */
2437 for (i = 0; i < stripes; i++)
2438 acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1;
2439 }
2440
2441 if (imgu_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr))
2442 return -EINVAL;
2443
2444 /* acc_param: ae_config */
2445
2446 if (use && use->acc_ae) {
2447 /* Take values from user */
2448 acc->ae.grid_cfg = acc_user->ae.grid_cfg;
2449 acc->ae.ae_ccm = acc_user->ae.ae_ccm;
2450 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2451 acc->ae.weights[i] = acc_user->ae.weights[i];
2452 } else if (acc_old) {
2453 /* Use old value */
2454 acc->ae.grid_cfg = acc_old->ae.grid_cfg;
2455 acc->ae.ae_ccm = acc_old->ae.ae_ccm;
2456 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2457 acc->ae.weights[i] = acc_old->ae.weights[i];
2458 } else {
2459 /* Set from scratch */
2460 static const struct ipu3_uapi_ae_weight_elem
2461 weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 };
2462
2463 acc->ae.grid_cfg = imgu_css_ae_grid_defaults;
2464 acc->ae.ae_ccm = imgu_css_ae_ccm_defaults;
2465 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
2466 acc->ae.weights[i] = weight_def;
2467 }
2468
2469 b_w_log2 = acc->ae.grid_cfg.block_width_log2;
2470 acc->ae.grid_cfg.x_end = imgu_css_grid_end(acc->ae.grid_cfg.x_start,
2471 acc->ae.grid_cfg.width,
2472 b_w_log2);
2473 b_w_log2 = acc->ae.grid_cfg.block_height_log2;
2474 acc->ae.grid_cfg.y_end = imgu_css_grid_end(acc->ae.grid_cfg.y_start,
2475 acc->ae.grid_cfg.height,
2476 b_w_log2);
2477
2478 for (i = 0; i < stripes; i++)
2479 acc->ae.stripes[i].grid = acc->ae.grid_cfg;
2480
2481 if (acc->ae.grid_cfg.x_start >=
2482 acc->stripe.down_scaled_stripes[1].offset) {
2483 /* Enable only for rightmost stripe, disable left */
2484 acc->ae.stripes[0].grid.ae_en = 0;
2485 } else if (acc->ae.grid_cfg.x_end <=
2486 acc->stripe.bds_out_stripes[0].width) {
2487 /* Enable only for leftmost stripe, disable right */
2488 acc->ae.stripes[1].grid.ae_en = 0;
2489 } else {
2490 /* Enable for both stripes */
2491 u8 b_w_log2;
2492
2493 acc->ae.stripes[0].grid.width =
2494 (acc->stripe.bds_out_stripes[0].width -
2495 acc->ae.grid_cfg.x_start + 1) >>
2496 acc->ae.grid_cfg.block_width_log2;
2497
2498 acc->ae.stripes[1].grid.width =
2499 acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width;
2500
2501 b_w_log2 = acc->ae.stripes[0].grid.block_width_log2;
2502 acc->ae.stripes[0].grid.x_end =
2503 imgu_css_grid_end(acc->ae.stripes[0].grid.x_start,
2504 acc->ae.stripes[0].grid.width,
2505 b_w_log2);
2506
2507 acc->ae.stripes[1].grid.x_start =
2508 (acc->ae.stripes[0].grid.x_end + 1 -
2509 acc->stripe.down_scaled_stripes[1].offset) &
2510 IPU3_UAPI_GRID_START_MASK;
2511 b_w_log2 = acc->ae.stripes[1].grid.block_width_log2;
2512 acc->ae.stripes[1].grid.x_end =
2513 imgu_css_grid_end(acc->ae.stripes[1].grid.x_start,
2514 acc->ae.stripes[1].grid.width,
2515 b_w_log2);
2516 }
2517
2518 /* acc_param: af_config */
2519
2520 if (use && use->acc_af) {
2521 /* Take values from user */
2522 acc->af.config.filter_config = acc_user->af.filter_config;
2523 acc->af.config.grid_cfg = acc_user->af.grid_cfg;
2524 } else if (acc_old) {
2525 /* Use old value */
2526 acc->af.config = acc_old->af.config;
2527 } else {
2528 /* Set from scratch */
2529 acc->af.config.filter_config =
2530 imgu_css_af_defaults.filter_config;
2531 acc->af.config.grid_cfg = imgu_css_af_defaults.grid_cfg;
2532 }
2533
2534 imgu_css_grid_end_calc(&acc->af.config.grid_cfg);
2535
2536 if (acc->af.config.grid_cfg.width <= 0)
2537 return -EINVAL;
2538
2539 acc->af.config.grid_cfg.height_per_slice =
2540 IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width;
2541 acc->af.config.frame_size.width =
2542 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
2543 acc->af.config.frame_size.height =
2544 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2545
2546 if (acc->stripe.bds_out_stripes[0].width <= min_overlap)
2547 return -EINVAL;
2548
2549 for (i = 0; i < stripes; i++) {
2550 acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg;
2551 acc->af.stripes[i].frame_size.height =
2552 css_pipe->rect[IPU3_CSS_RECT_BDS].height;
2553 acc->af.stripes[i].frame_size.width =
2554 acc->stripe.bds_out_stripes[i].width;
2555 }
2556
2557 if (acc->af.config.grid_cfg.x_start >=
2558 acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2559 /* Enable only for rightmost stripe, disable left */
2560 acc->af.stripes[0].grid_cfg.y_start &=
2561 ~IPU3_UAPI_GRID_Y_START_EN;
2562 } else if (acc->af.config.grid_cfg.x_end <=
2563 acc->stripe.bds_out_stripes[0].width - min_overlap) {
2564 /* Enable only for leftmost stripe, disable right */
2565 acc->af.stripes[1].grid_cfg.y_start &=
2566 ~IPU3_UAPI_GRID_Y_START_EN;
2567 } else {
2568 /* Enable for both stripes */
2569
2570 acc->af.stripes[0].grid_cfg.width =
2571 (acc->stripe.bds_out_stripes[0].width - min_overlap -
2572 acc->af.config.grid_cfg.x_start + 1) >>
2573 acc->af.config.grid_cfg.block_width_log2;
2574 acc->af.stripes[1].grid_cfg.width =
2575 acc->af.config.grid_cfg.width -
2576 acc->af.stripes[0].grid_cfg.width;
2577
2578 b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2;
2579 acc->af.stripes[0].grid_cfg.x_end =
2580 imgu_css_grid_end(acc->af.stripes[0].grid_cfg.x_start,
2581 acc->af.stripes[0].grid_cfg.width,
2582 b_w_log2);
2583
2584 acc->af.stripes[1].grid_cfg.x_start =
2585 (acc->af.stripes[0].grid_cfg.x_end + 1 -
2586 acc->stripe.down_scaled_stripes[1].offset) &
2587 IPU3_UAPI_GRID_START_MASK;
2588
2589 b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2;
2590 acc->af.stripes[1].grid_cfg.x_end =
2591 imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start,
2592 acc->af.stripes[1].grid_cfg.width,
2593 b_w_log2);
2594
2595 /*
2596 * To reduce complexity of debubbling and loading statistics
2597 * fix grid_height_per_slice to 1 for both stripes
2598 */
2599 for (i = 0; i < stripes; i++)
2600 acc->af.stripes[i].grid_cfg.height_per_slice = 1;
2601 }
2602
2603 if (imgu_css_af_ops_calc(css, pipe, &acc->af))
2604 return -EINVAL;
2605
2606 /* acc_param: awb_config */
2607
2608 if (use && use->acc_awb) {
2609 /* Take values from user */
2610 acc->awb.config = acc_user->awb.config;
2611 } else if (acc_old) {
2612 /* Use old value */
2613 acc->awb.config = acc_old->awb.config;
2614 } else {
2615 /* Set from scratch */
2616 acc->awb.config = imgu_css_awb_defaults;
2617 }
2618
2619 if (acc->awb.config.grid.width <= 0)
2620 return -EINVAL;
2621
2622 acc->awb.config.grid.height_per_slice =
2623 IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width,
2624 imgu_css_grid_end_calc(&acc->awb.config.grid);
2625
2626 for (i = 0; i < stripes; i++)
2627 acc->awb.stripes[i] = acc->awb.config;
2628
2629 if (acc->awb.config.grid.x_start >=
2630 acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
2631 /* Enable only for rightmost stripe, disable left */
2632 acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
2633 } else if (acc->awb.config.grid.x_end <=
2634 acc->stripe.bds_out_stripes[0].width - min_overlap) {
2635 /* Enable only for leftmost stripe, disable right */
2636 acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
2637 } else {
2638 /* Enable for both stripes */
2639
2640 acc->awb.stripes[0].grid.width =
2641 (acc->stripe.bds_out_stripes[0].width -
2642 acc->awb.config.grid.x_start + 1) >>
2643 acc->awb.config.grid.block_width_log2;
2644 acc->awb.stripes[1].grid.width = acc->awb.config.grid.width -
2645 acc->awb.stripes[0].grid.width;
2646
2647 b_w_log2 = acc->awb.stripes[0].grid.block_width_log2;
2648 acc->awb.stripes[0].grid.x_end =
2649 imgu_css_grid_end(acc->awb.stripes[0].grid.x_start,
2650 acc->awb.stripes[0].grid.width,
2651 b_w_log2);
2652
2653 acc->awb.stripes[1].grid.x_start =
2654 (acc->awb.stripes[0].grid.x_end + 1 -
2655 acc->stripe.down_scaled_stripes[1].offset) &
2656 IPU3_UAPI_GRID_START_MASK;
2657
2658 b_w_log2 = acc->awb.stripes[1].grid.block_width_log2;
2659 acc->awb.stripes[1].grid.x_end =
2660 imgu_css_grid_end(acc->awb.stripes[1].grid.x_start,
2661 acc->awb.stripes[1].grid.width,
2662 b_w_log2);
2663
2664 /*
2665 * To reduce complexity of debubbling and loading statistics
2666 * fix grid_height_per_slice to 1 for both stripes
2667 */
2668 for (i = 0; i < stripes; i++)
2669 acc->awb.stripes[i].grid.height_per_slice = 1;
2670 }
2671
2672 if (imgu_css_awb_ops_calc(css, pipe, &acc->awb))
2673 return -EINVAL;
2674
2675 return 0;
2676 }
2677
2678 /*
2679 * Fill the indicated structure in `new_binary_params' from the possible
2680 * sources based on `use_user' flag: if the flag is false, copy from
2681 * `old_binary_params', or if the flag is true, copy from `user_setting'
2682 * and return NULL (or error pointer on error).
2683 * If the flag is false and `old_binary_params' is NULL, return pointer
2684 * to the structure inside `new_binary_params'. In that case the caller
2685 * should calculate and fill the structure from scratch.
2686 */
imgu_css_cfg_copy(struct imgu_css * css,unsigned int pipe,bool use_user,void * user_setting,void * old_binary_params,void * new_binary_params,enum imgu_abi_memories m,struct imgu_fw_isp_parameter * par,size_t par_size)2687 static void *imgu_css_cfg_copy(struct imgu_css *css,
2688 unsigned int pipe, bool use_user,
2689 void *user_setting, void *old_binary_params,
2690 void *new_binary_params,
2691 enum imgu_abi_memories m,
2692 struct imgu_fw_isp_parameter *par,
2693 size_t par_size)
2694 {
2695 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2696 void *new_setting, *old_setting;
2697
2698 new_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par,
2699 par_size, new_binary_params);
2700 if (!new_setting)
2701 return ERR_PTR(-EPROTO); /* Corrupted firmware */
2702
2703 if (use_user) {
2704 /* Take new user parameters */
2705 memcpy(new_setting, user_setting, par_size);
2706 } else if (old_binary_params) {
2707 /* Take previous value */
2708 old_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par,
2709 par_size,
2710 old_binary_params);
2711 if (!old_setting)
2712 return ERR_PTR(-EPROTO);
2713 memcpy(new_setting, old_setting, par_size);
2714 } else {
2715 return new_setting; /* Need to calculate */
2716 }
2717
2718 return NULL; /* Copied from other value */
2719 }
2720
2721 /*
2722 * Configure VMEM0 parameters (late binding parameters).
2723 */
imgu_css_cfg_vmem0(struct imgu_css * css,unsigned int pipe,struct ipu3_uapi_flags * use,void * vmem0,void * vmem0_old,struct ipu3_uapi_params * user)2724 int imgu_css_cfg_vmem0(struct imgu_css *css, unsigned int pipe,
2725 struct ipu3_uapi_flags *use,
2726 void *vmem0, void *vmem0_old,
2727 struct ipu3_uapi_params *user)
2728 {
2729 const struct imgu_fw_info *bi =
2730 &css->fwp->binary_header[css->pipes[pipe].bindex];
2731 struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
2732 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
2733 struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL;
2734 struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem = NULL;
2735 struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem = NULL;
2736 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2737 const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0;
2738 unsigned int i;
2739
2740 /* Configure VMEM0 */
2741
2742 memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
2743
2744 /* Configure Linearization VMEM0 parameters */
2745
2746 lin_vmem = imgu_css_cfg_copy(css, pipe, use && use->lin_vmem_params,
2747 &user->lin_vmem_params, vmem0_old, vmem0,
2748 m, &pofs->vmem.lin, sizeof(*lin_vmem));
2749 if (!IS_ERR_OR_NULL(lin_vmem)) {
2750 /* Generate parameter from scratch */
2751 for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) {
2752 lin_vmem->lin_lutlow_gr[i] = 32 * i;
2753 lin_vmem->lin_lutlow_r[i] = 32 * i;
2754 lin_vmem->lin_lutlow_b[i] = 32 * i;
2755 lin_vmem->lin_lutlow_gb[i] = 32 * i;
2756
2757 lin_vmem->lin_lutdif_gr[i] = 32;
2758 lin_vmem->lin_lutdif_r[i] = 32;
2759 lin_vmem->lin_lutdif_b[i] = 32;
2760 lin_vmem->lin_lutdif_gb[i] = 32;
2761 }
2762 }
2763
2764 /* Configure TNR3 VMEM parameters */
2765 if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
2766 tnr_vmem = imgu_css_cfg_copy(css, pipe,
2767 use && use->tnr3_vmem_params,
2768 &user->tnr3_vmem_params,
2769 vmem0_old, vmem0, m,
2770 &pofs->vmem.tnr3,
2771 sizeof(*tnr_vmem));
2772 if (!IS_ERR_OR_NULL(tnr_vmem)) {
2773 /* Generate parameter from scratch */
2774 for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++)
2775 tnr_vmem->sigma[i] = 256;
2776 }
2777 }
2778 i = IPU3_UAPI_ISP_TNR3_VMEM_LEN;
2779
2780 /* Configure XNR3 VMEM parameters */
2781
2782 xnr_vmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params,
2783 &user->xnr3_vmem_params, vmem0_old, vmem0,
2784 m, &pofs->vmem.xnr3, sizeof(*xnr_vmem));
2785 if (!IS_ERR_OR_NULL(xnr_vmem)) {
2786 xnr_vmem->x[i] = imgu_css_xnr3_vmem_defaults.x
2787 [i % IMGU_XNR3_VMEM_LUT_LEN];
2788 xnr_vmem->a[i] = imgu_css_xnr3_vmem_defaults.a
2789 [i % IMGU_XNR3_VMEM_LUT_LEN];
2790 xnr_vmem->b[i] = imgu_css_xnr3_vmem_defaults.b
2791 [i % IMGU_XNR3_VMEM_LUT_LEN];
2792 xnr_vmem->c[i] = imgu_css_xnr3_vmem_defaults.c
2793 [i % IMGU_XNR3_VMEM_LUT_LEN];
2794 }
2795
2796 return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ?
2797 -EPROTO : 0;
2798 }
2799
2800 /*
2801 * Configure DMEM0 parameters (late binding parameters).
2802 */
imgu_css_cfg_dmem0(struct imgu_css * css,unsigned int pipe,struct ipu3_uapi_flags * use,void * dmem0,void * dmem0_old,struct ipu3_uapi_params * user)2803 int imgu_css_cfg_dmem0(struct imgu_css *css, unsigned int pipe,
2804 struct ipu3_uapi_flags *use,
2805 void *dmem0, void *dmem0_old,
2806 struct ipu3_uapi_params *user)
2807 {
2808 struct imgu_css_pipe *css_pipe = &css->pipes[pipe];
2809 const struct imgu_fw_info *bi =
2810 &css->fwp->binary_header[css_pipe->bindex];
2811 struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
2812 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
2813
2814 struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL;
2815 struct ipu3_uapi_isp_xnr3_params *xnr_dmem;
2816
2817 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
2818 const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0;
2819
2820 /* Configure DMEM0 */
2821
2822 memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
2823
2824 /* Configure TNR3 DMEM0 parameters */
2825 if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
2826 tnr_dmem = imgu_css_cfg_copy(css, pipe,
2827 use && use->tnr3_dmem_params,
2828 &user->tnr3_dmem_params,
2829 dmem0_old, dmem0, m,
2830 &pofs->dmem.tnr3,
2831 sizeof(*tnr_dmem));
2832 if (!IS_ERR_OR_NULL(tnr_dmem)) {
2833 /* Generate parameter from scratch */
2834 tnr_dmem->knee_y1 = 768;
2835 tnr_dmem->knee_y2 = 1280;
2836 }
2837 }
2838
2839 /* Configure XNR3 DMEM0 parameters */
2840
2841 xnr_dmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params,
2842 &user->xnr3_dmem_params, dmem0_old, dmem0,
2843 m, &pofs->dmem.xnr3, sizeof(*xnr_dmem));
2844 if (!IS_ERR_OR_NULL(xnr_dmem)) {
2845 /* Generate parameter from scratch */
2846 xnr_dmem->alpha.y0 = 2047;
2847 xnr_dmem->alpha.u0 = 2047;
2848 xnr_dmem->alpha.v0 = 2047;
2849 }
2850
2851 return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0;
2852 }
2853
2854 /* Generate unity morphing table without morphing effect */
imgu_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param * gdc,int frame_in_x,int frame_in_y,int frame_out_x,int frame_out_y,int env_w,int env_h)2855 void imgu_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc,
2856 int frame_in_x, int frame_in_y,
2857 int frame_out_x, int frame_out_y,
2858 int env_w, int env_h)
2859 {
2860 static const unsigned int FRAC_BITS = IMGU_ABI_GDC_FRAC_BITS;
2861 static const unsigned int XMEM_ALIGN = 1 << 4;
2862 const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1);
2863 static const unsigned int BCI_ENV = 4;
2864 static const unsigned int BYP = 2; /* Bytes per pixel */
2865 const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + env_w + 1;
2866 const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + env_h + 1;
2867
2868 struct imgu_abi_gdc_warp_param gdc_luma, gdc_chroma;
2869
2870 unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x,
2871 IMGU_DVS_BLOCK_W), 2);
2872 unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H);
2873 unsigned int y0, x0, x1, x, y;
2874
2875 /* Global luma settings */
2876 gdc_luma.origin_x = 0;
2877 gdc_luma.origin_y = 0;
2878 gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << FRAC_BITS;
2879 gdc_luma.p0_y = 0;
2880 gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
2881 gdc_luma.p1_y = gdc_luma.p0_y;
2882 gdc_luma.p2_x = gdc_luma.p0_x;
2883 gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << FRAC_BITS);
2884 gdc_luma.p3_x = gdc_luma.p1_x;
2885 gdc_luma.p3_y = gdc_luma.p2_y;
2886
2887 gdc_luma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV +
2888 OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK);
2889 gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width,
2890 IPU3_UAPI_ISP_VEC_ELEMS);
2891 gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width,
2892 IMGU_ABI_ISP_DDR_WORD_BYTES /
2893 BYP);
2894 gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV;
2895 gdc_luma.padding = 0;
2896
2897 /* Global chroma settings */
2898 gdc_chroma.origin_x = 0;
2899 gdc_chroma.origin_y = 0;
2900 gdc_chroma.p0_x = (OFFSET_X / 2 - (OFFSET_X / 2 & XMEM_ALIGN_MASK)) <<
2901 FRAC_BITS;
2902 gdc_chroma.p0_y = 0;
2903 gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS);
2904 gdc_chroma.p1_y = gdc_chroma.p0_y;
2905 gdc_chroma.p2_x = gdc_chroma.p0_x;
2906 gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << FRAC_BITS);
2907 gdc_chroma.p3_x = gdc_chroma.p1_x;
2908 gdc_chroma.p3_y = gdc_chroma.p2_y;
2909
2910 gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV;
2911 gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width,
2912 IPU3_UAPI_ISP_VEC_ELEMS);
2913 gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width,
2914 IMGU_ABI_ISP_DDR_WORD_BYTES /
2915 BYP);
2916 gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV;
2917 gdc_chroma.padding = 0;
2918
2919 /* Calculate block offsets for luma and chroma */
2920 for (y0 = 0; y0 < blocks_y; y0++) {
2921 for (x0 = 0; x0 < blocks_x / 2; x0++) {
2922 for (x1 = 0; x1 < 2; x1++) {
2923 /* Luma blocks */
2924 x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X;
2925 x &= XMEM_ALIGN_MASK;
2926 y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y;
2927 *gdc = gdc_luma;
2928 gdc->in_addr_offset =
2929 (y * frame_in_x + x) * BYP;
2930 gdc++;
2931 }
2932
2933 /* Chroma block */
2934 x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2;
2935 x &= XMEM_ALIGN_MASK;
2936 y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2;
2937 *gdc = gdc_chroma;
2938 gdc->in_addr_offset = (y * frame_in_x + x) * BYP;
2939 gdc++;
2940 }
2941 }
2942 }
2943