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