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