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