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