]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/ifmtr/src/ifmtr.c
Merge remote-tracking branches 'spi/fix/armada', 'spi/fix/atmel', 'spi/fix/doc',...
[mirror_ubuntu-hirsute-kernel.git] / drivers / staging / media / atomisp / pci / atomisp2 / css2400 / runtime / ifmtr / src / ifmtr.c
1 #ifndef ISP2401
2 /*
3 * Support for Intel Camera Imaging ISP subsystem.
4 * Copyright (c) 2015, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15 #else
16 /*
17 Support for Intel Camera Imaging ISP subsystem.
18 Copyright (c) 2010 - 2015, Intel Corporation.
19
20 This program is free software; you can redistribute it and/or modify it
21 under the terms and conditions of the GNU General Public License,
22 version 2, as published by the Free Software Foundation.
23
24 This program is distributed in the hope it will be useful, but WITHOUT
25 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
27 more details.
28 */
29 #endif
30
31 #include "system_global.h"
32 #include <linux/kernel.h>
33
34 #ifdef USE_INPUT_SYSTEM_VERSION_2
35
36 #include "ia_css_ifmtr.h"
37 #include <math_support.h>
38 #include "sh_css_internal.h"
39 #include "input_formatter.h"
40 #include "assert_support.h"
41 #include "sh_css_sp.h"
42 #include "isp/modes/interface/input_buf.isp.h"
43
44 /************************************************************
45 * Static functions declarations
46 ************************************************************/
47 static enum ia_css_err ifmtr_start_column(
48 const struct ia_css_stream_config *config,
49 unsigned int bin_in,
50 unsigned int *start_column);
51
52 static enum ia_css_err ifmtr_input_start_line(
53 const struct ia_css_stream_config *config,
54 unsigned int bin_in,
55 unsigned int *start_line);
56
57 static void ifmtr_set_if_blocking_mode(
58 const input_formatter_cfg_t * const config_a,
59 const input_formatter_cfg_t * const config_b);
60
61 /************************************************************
62 * Public functions
63 ************************************************************/
64
65 /* ISP expects GRBG bayer order, we skip one line and/or one row
66 * to correct in case the input bayer order is different.
67 */
68 unsigned int ia_css_ifmtr_lines_needed_for_bayer_order(
69 const struct ia_css_stream_config *config)
70 {
71 assert(config != NULL);
72 if ((IA_CSS_BAYER_ORDER_BGGR == config->input_config.bayer_order)
73 || (IA_CSS_BAYER_ORDER_GBRG == config->input_config.bayer_order))
74 return 1;
75
76 return 0;
77 }
78
79 unsigned int ia_css_ifmtr_columns_needed_for_bayer_order(
80 const struct ia_css_stream_config *config)
81 {
82 assert(config != NULL);
83 if ((IA_CSS_BAYER_ORDER_RGGB == config->input_config.bayer_order)
84 || (IA_CSS_BAYER_ORDER_GBRG == config->input_config.bayer_order))
85 return 1;
86
87 return 0;
88 }
89
90 enum ia_css_err ia_css_ifmtr_configure(struct ia_css_stream_config *config,
91 struct ia_css_binary *binary)
92 {
93 unsigned int start_line, start_column = 0,
94 cropped_height,
95 cropped_width,
96 num_vectors,
97 buffer_height = 2,
98 buffer_width,
99 two_ppc,
100 vmem_increment = 0,
101 deinterleaving = 0,
102 deinterleaving_b = 0,
103 width_a = 0,
104 width_b = 0,
105 bits_per_pixel,
106 vectors_per_buffer,
107 vectors_per_line = 0,
108 buffers_per_line = 0,
109 buf_offset_a = 0,
110 buf_offset_b = 0,
111 line_width = 0,
112 width_b_factor = 1, start_column_b,
113 left_padding = 0;
114 input_formatter_cfg_t if_a_config, if_b_config;
115 enum ia_css_stream_format input_format;
116 enum ia_css_err err = IA_CSS_SUCCESS;
117 uint8_t if_config_index;
118
119 /* Determine which input formatter config set is targeted. */
120 /* Index is equal to the CSI-2 port used. */
121 enum ia_css_csi2_port port;
122
123 if (binary) {
124 cropped_height = binary->in_frame_info.res.height;
125 cropped_width = binary->in_frame_info.res.width;
126 /* This should correspond to the input buffer definition for
127 ISP binaries in input_buf.isp.h */
128 if (binary->info->sp.enable.continuous && binary->info->sp.pipeline.mode != IA_CSS_BINARY_MODE_COPY)
129 buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
130 else
131 buffer_width = binary->info->sp.input.max_width;
132 input_format = binary->input_format;
133 } else {
134 /* sp raw copy pipe (IA_CSS_PIPE_MODE_COPY): binary is NULL */
135 cropped_height = config->input_config.input_res.height;
136 cropped_width = config->input_config.input_res.width;
137 buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
138 input_format = config->input_config.format;
139 }
140 two_ppc = config->pixels_per_clock == 2;
141 if (config->mode == IA_CSS_INPUT_MODE_SENSOR
142 || config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
143 port = config->source.port.port;
144 if_config_index = (uint8_t) (port - IA_CSS_CSI2_PORT0);
145 } else if (config->mode == IA_CSS_INPUT_MODE_MEMORY) {
146 if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED;
147 } else {
148 if_config_index = 0;
149 }
150
151 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS
152 || if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED);
153
154 /* TODO: check to see if input is RAW and if current mode interprets
155 * RAW data in any particular bayer order. copy binary with output
156 * format other than raw should not result in dropping lines and/or
157 * columns.
158 */
159 err = ifmtr_input_start_line(config, cropped_height, &start_line);
160 if (err != IA_CSS_SUCCESS)
161 return err;
162 err = ifmtr_start_column(config, cropped_width, &start_column);
163 if (err != IA_CSS_SUCCESS)
164 return err;
165
166 if (config->left_padding == -1)
167 if (!binary)
168 /* sp raw copy pipe: set left_padding value */
169 left_padding = 0;
170 else
171 left_padding = binary->left_padding;
172 else
173 left_padding = 2*ISP_VEC_NELEMS - config->left_padding;
174
175
176 if (left_padding) {
177 num_vectors = CEIL_DIV(cropped_width + left_padding,
178 ISP_VEC_NELEMS);
179 } else {
180 num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
181 num_vectors *= buffer_height;
182 /* todo: in case of left padding,
183 num_vectors is vectors per line,
184 otherwise vectors per line * buffer_height. */
185 }
186
187 start_column_b = start_column;
188
189 bits_per_pixel = input_formatter_get_alignment(INPUT_FORMATTER0_ID)
190 * 8 / ISP_VEC_NELEMS;
191 switch (input_format) {
192 case IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY:
193 if (two_ppc) {
194 vmem_increment = 1;
195 deinterleaving = 1;
196 deinterleaving_b = 1;
197 /* half lines */
198 width_a = cropped_width * deinterleaving / 2;
199 width_b_factor = 2;
200 /* full lines */
201 width_b = width_a * width_b_factor;
202 buffer_width *= deinterleaving * 2;
203 /* Patch from bayer to yuv */
204 num_vectors *= deinterleaving;
205 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
206 vectors_per_line = num_vectors / buffer_height;
207 /* Even lines are half size */
208 line_width = vectors_per_line *
209 input_formatter_get_alignment(INPUT_FORMATTER0_ID) /
210 2;
211 start_column /= 2;
212 } else {
213 vmem_increment = 1;
214 deinterleaving = 3;
215 width_a = cropped_width * deinterleaving / 2;
216 buffer_width = buffer_width * deinterleaving / 2;
217 /* Patch from bayer to yuv */
218 num_vectors = num_vectors / 2 * deinterleaving;
219 start_column = start_column * deinterleaving / 2;
220 }
221 break;
222 case IA_CSS_STREAM_FORMAT_YUV420_8:
223 case IA_CSS_STREAM_FORMAT_YUV420_10:
224 case IA_CSS_STREAM_FORMAT_YUV420_16:
225 if (two_ppc) {
226 vmem_increment = 1;
227 deinterleaving = 1;
228 width_a = width_b = cropped_width * deinterleaving / 2;
229 buffer_width *= deinterleaving * 2;
230 num_vectors *= deinterleaving;
231 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
232 vectors_per_line = num_vectors / buffer_height;
233 /* Even lines are half size */
234 line_width = vectors_per_line *
235 input_formatter_get_alignment(INPUT_FORMATTER0_ID) /
236 2;
237 start_column *= deinterleaving;
238 start_column /= 2;
239 start_column_b = start_column;
240 } else {
241 vmem_increment = 1;
242 deinterleaving = 1;
243 width_a = cropped_width * deinterleaving;
244 buffer_width *= deinterleaving * 2;
245 num_vectors *= deinterleaving;
246 start_column *= deinterleaving;
247 }
248 break;
249 case IA_CSS_STREAM_FORMAT_YUV422_8:
250 case IA_CSS_STREAM_FORMAT_YUV422_10:
251 case IA_CSS_STREAM_FORMAT_YUV422_16:
252 if (two_ppc) {
253 vmem_increment = 1;
254 deinterleaving = 1;
255 width_a = width_b = cropped_width * deinterleaving;
256 buffer_width *= deinterleaving * 2;
257 num_vectors *= deinterleaving;
258 start_column *= deinterleaving;
259 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
260 start_column_b = start_column;
261 } else {
262 vmem_increment = 1;
263 deinterleaving = 2;
264 width_a = cropped_width * deinterleaving;
265 buffer_width *= deinterleaving;
266 num_vectors *= deinterleaving;
267 start_column *= deinterleaving;
268 }
269 break;
270 case IA_CSS_STREAM_FORMAT_RGB_444:
271 case IA_CSS_STREAM_FORMAT_RGB_555:
272 case IA_CSS_STREAM_FORMAT_RGB_565:
273 case IA_CSS_STREAM_FORMAT_RGB_666:
274 case IA_CSS_STREAM_FORMAT_RGB_888:
275 num_vectors *= 2;
276 if (two_ppc) {
277 deinterleaving = 2; /* BR in if_a, G in if_b */
278 deinterleaving_b = 1; /* BR in if_a, G in if_b */
279 buffers_per_line = 4;
280 start_column_b = start_column;
281 start_column *= deinterleaving;
282 start_column_b *= deinterleaving_b;
283 } else {
284 deinterleaving = 3; /* BGR */
285 buffers_per_line = 3;
286 start_column *= deinterleaving;
287 }
288 vmem_increment = 1;
289 width_a = cropped_width * deinterleaving;
290 width_b = cropped_width * deinterleaving_b;
291 buffer_width *= buffers_per_line;
292 /* Patch from bayer to rgb */
293 num_vectors = num_vectors / 2 * deinterleaving;
294 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
295 break;
296 case IA_CSS_STREAM_FORMAT_RAW_6:
297 case IA_CSS_STREAM_FORMAT_RAW_7:
298 case IA_CSS_STREAM_FORMAT_RAW_8:
299 case IA_CSS_STREAM_FORMAT_RAW_10:
300 case IA_CSS_STREAM_FORMAT_RAW_12:
301 if (two_ppc) {
302 int crop_col = (start_column % 2) == 1;
303 vmem_increment = 2;
304 deinterleaving = 1;
305 width_a = width_b = cropped_width / 2;
306
307 /* When two_ppc is enabled AND we need to crop one extra
308 * column, if_a crops by one extra and we swap the
309 * output offsets to interleave the bayer pattern in
310 * the correct order.
311 */
312 buf_offset_a = crop_col ? 1 : 0;
313 buf_offset_b = crop_col ? 0 : 1;
314 start_column_b = start_column / 2;
315 start_column = start_column / 2 + crop_col;
316 } else {
317 vmem_increment = 1;
318 deinterleaving = 2;
319 if ((!binary) || (config->continuous && binary
320 && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)) {
321 /* !binary -> sp raw copy pipe, no deinterleaving */
322 deinterleaving = 1;
323 }
324 width_a = cropped_width;
325 /* Must be multiple of deinterleaving */
326 num_vectors = CEIL_MUL(num_vectors, deinterleaving);
327 }
328 buffer_height *= 2;
329 if ((!binary) || config->continuous)
330 /* !binary -> sp raw copy pipe */
331 buffer_height *= 2;
332 vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
333 vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving);
334 break;
335 case IA_CSS_STREAM_FORMAT_RAW_14:
336 case IA_CSS_STREAM_FORMAT_RAW_16:
337 if (two_ppc) {
338 num_vectors *= 2;
339 vmem_increment = 1;
340 deinterleaving = 2;
341 width_a = width_b = cropped_width;
342 /* B buffer is one line further */
343 buf_offset_b = buffer_width / ISP_VEC_NELEMS;
344 bits_per_pixel *= 2;
345 } else {
346 vmem_increment = 1;
347 deinterleaving = 2;
348 width_a = cropped_width;
349 start_column /= deinterleaving;
350 }
351 buffer_height *= 2;
352 break;
353 case IA_CSS_STREAM_FORMAT_BINARY_8:
354 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT1:
355 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT2:
356 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT3:
357 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT4:
358 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT5:
359 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT6:
360 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT7:
361 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT8:
362 case IA_CSS_STREAM_FORMAT_YUV420_8_SHIFT:
363 case IA_CSS_STREAM_FORMAT_YUV420_10_SHIFT:
364 case IA_CSS_STREAM_FORMAT_EMBEDDED:
365 case IA_CSS_STREAM_FORMAT_USER_DEF1:
366 case IA_CSS_STREAM_FORMAT_USER_DEF2:
367 case IA_CSS_STREAM_FORMAT_USER_DEF3:
368 case IA_CSS_STREAM_FORMAT_USER_DEF4:
369 case IA_CSS_STREAM_FORMAT_USER_DEF5:
370 case IA_CSS_STREAM_FORMAT_USER_DEF6:
371 case IA_CSS_STREAM_FORMAT_USER_DEF7:
372 case IA_CSS_STREAM_FORMAT_USER_DEF8:
373 break;
374 }
375 if (width_a == 0)
376 return IA_CSS_ERR_INVALID_ARGUMENTS;
377
378 if (two_ppc)
379 left_padding /= 2;
380
381 /* Default values */
382 if (left_padding)
383 vectors_per_line = num_vectors;
384 if (!vectors_per_line) {
385 vectors_per_line = CEIL_MUL(num_vectors / buffer_height,
386 deinterleaving);
387 line_width = 0;
388 }
389 if (!line_width)
390 line_width = vectors_per_line *
391 input_formatter_get_alignment(INPUT_FORMATTER0_ID);
392 if (!buffers_per_line)
393 buffers_per_line = deinterleaving;
394 line_width = CEIL_MUL(line_width,
395 input_formatter_get_alignment(INPUT_FORMATTER0_ID)
396 * vmem_increment);
397
398 vectors_per_buffer = buffer_height * buffer_width / ISP_VEC_NELEMS;
399
400 if (config->mode == IA_CSS_INPUT_MODE_TPG &&
401 ((binary && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO) ||
402 (!binary))) {
403 /* !binary -> sp raw copy pipe */
404 /* workaround for TPG in video mode */
405 start_line = 0;
406 start_column = 0;
407 cropped_height -= start_line;
408 width_a -= start_column;
409 }
410
411 if_a_config.start_line = start_line;
412 if_a_config.start_column = start_column;
413 if_a_config.left_padding = left_padding / deinterleaving;
414 if_a_config.cropped_height = cropped_height;
415 if_a_config.cropped_width = width_a;
416 if_a_config.deinterleaving = deinterleaving;
417 if_a_config.buf_vecs = vectors_per_buffer;
418 if_a_config.buf_start_index = buf_offset_a;
419 if_a_config.buf_increment = vmem_increment;
420 if_a_config.buf_eol_offset =
421 buffer_width * bits_per_pixel / 8 - line_width;
422 if_a_config.is_yuv420_format =
423 (input_format == IA_CSS_STREAM_FORMAT_YUV420_8)
424 || (input_format == IA_CSS_STREAM_FORMAT_YUV420_10)
425 || (input_format == IA_CSS_STREAM_FORMAT_YUV420_16);
426 if_a_config.block_no_reqs = (config->mode != IA_CSS_INPUT_MODE_SENSOR);
427
428 if (two_ppc) {
429 if (deinterleaving_b) {
430 deinterleaving = deinterleaving_b;
431 width_b = cropped_width * deinterleaving;
432 buffer_width *= deinterleaving;
433 /* Patch from bayer to rgb */
434 num_vectors = num_vectors / 2 *
435 deinterleaving * width_b_factor;
436 vectors_per_line = num_vectors / buffer_height;
437 line_width = vectors_per_line *
438 input_formatter_get_alignment(INPUT_FORMATTER0_ID);
439 }
440 if_b_config.start_line = start_line;
441 if_b_config.start_column = start_column_b;
442 if_b_config.left_padding = left_padding / deinterleaving;
443 if_b_config.cropped_height = cropped_height;
444 if_b_config.cropped_width = width_b;
445 if_b_config.deinterleaving = deinterleaving;
446 if_b_config.buf_vecs = vectors_per_buffer;
447 if_b_config.buf_start_index = buf_offset_b;
448 if_b_config.buf_increment = vmem_increment;
449 if_b_config.buf_eol_offset =
450 buffer_width * bits_per_pixel / 8 - line_width;
451 if_b_config.is_yuv420_format =
452 input_format == IA_CSS_STREAM_FORMAT_YUV420_8
453 || input_format == IA_CSS_STREAM_FORMAT_YUV420_10
454 || input_format == IA_CSS_STREAM_FORMAT_YUV420_16;
455 if_b_config.block_no_reqs =
456 (config->mode != IA_CSS_INPUT_MODE_SENSOR);
457
458 if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) {
459 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
460
461 ifmtr_set_if_blocking_mode(&if_a_config, &if_b_config);
462 /* Set the ifconfigs to SP group */
463 sh_css_sp_set_if_configs(&if_a_config, &if_b_config,
464 if_config_index);
465 }
466 } else {
467 if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) {
468 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
469
470 ifmtr_set_if_blocking_mode(&if_a_config, NULL);
471 /* Set the ifconfigs to SP group */
472 sh_css_sp_set_if_configs(&if_a_config, NULL,
473 if_config_index);
474 }
475 }
476
477 return IA_CSS_SUCCESS;
478 }
479
480 bool ifmtr_set_if_blocking_mode_reset = true;
481
482 /************************************************************
483 * Static functions
484 ************************************************************/
485 static void ifmtr_set_if_blocking_mode(
486 const input_formatter_cfg_t * const config_a,
487 const input_formatter_cfg_t * const config_b)
488 {
489 int i;
490 bool block[] = { false, false, false, false };
491 assert(N_INPUT_FORMATTER_ID <= (ARRAY_SIZE(block)));
492
493 #if !defined(IS_ISP_2400_SYSTEM)
494 #error "ifmtr_set_if_blocking_mode: ISP_SYSTEM must be one of {IS_ISP_2400_SYSTEM}"
495 #endif
496
497 block[INPUT_FORMATTER0_ID] = (bool)config_a->block_no_reqs;
498 if (NULL != config_b)
499 block[INPUT_FORMATTER1_ID] = (bool)config_b->block_no_reqs;
500
501 /* TODO: next could cause issues when streams are started after
502 * eachother. */
503 /*IF should not be reconfigured/reset from host */
504 if (ifmtr_set_if_blocking_mode_reset) {
505 ifmtr_set_if_blocking_mode_reset = false;
506 for (i = 0; i < N_INPUT_FORMATTER_ID; i++) {
507 input_formatter_ID_t id = (input_formatter_ID_t) i;
508 input_formatter_rst(id);
509 input_formatter_set_fifo_blocking_mode(id, block[id]);
510 }
511 }
512
513 return;
514 }
515
516 static enum ia_css_err ifmtr_start_column(
517 const struct ia_css_stream_config *config,
518 unsigned int bin_in,
519 unsigned int *start_column)
520 {
521 unsigned int in = config->input_config.input_res.width, start,
522 for_bayer = ia_css_ifmtr_columns_needed_for_bayer_order(config);
523
524 if (bin_in + 2 * for_bayer > in)
525 return IA_CSS_ERR_INVALID_ARGUMENTS;
526
527 /* On the hardware, we want to use the middle of the input, so we
528 * divide the start column by 2. */
529 start = (in - bin_in) / 2;
530 /* in case the number of extra columns is 2 or odd, we round the start
531 * column down */
532 start &= ~0x1;
533
534 /* now we add the one column (if needed) to correct for the bayer
535 * order).
536 */
537 start += for_bayer;
538 *start_column = start;
539 return IA_CSS_SUCCESS;
540 }
541
542 static enum ia_css_err ifmtr_input_start_line(
543 const struct ia_css_stream_config *config,
544 unsigned int bin_in,
545 unsigned int *start_line)
546 {
547 unsigned int in = config->input_config.input_res.height, start,
548 for_bayer = ia_css_ifmtr_lines_needed_for_bayer_order(config);
549
550 if (bin_in + 2 * for_bayer > in)
551 return IA_CSS_ERR_INVALID_ARGUMENTS;
552
553 /* On the hardware, we want to use the middle of the input, so we
554 * divide the start line by 2. On the simulator, we cannot handle extra
555 * lines at the end of the frame.
556 */
557 start = (in - bin_in) / 2;
558 /* in case the number of extra lines is 2 or odd, we round the start
559 * line down.
560 */
561 start &= ~0x1;
562
563 /* now we add the one line (if needed) to correct for the bayer order */
564 start += for_bayer;
565 *start_line = start;
566 return IA_CSS_SUCCESS;
567 }
568
569 #endif