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