3 * Support for Intel Camera Imaging ISP subsystem.
4 * Copyright (c) 2015, Intel Corporation.
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.
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
17 Support for Intel Camera Imaging ISP subsystem.
18 Copyright (c) 2010 - 2015, Intel Corporation.
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.
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
31 #include "system_global.h"
33 #ifdef USE_INPUT_SYSTEM_VERSION_2
35 #include "ia_css_ifmtr.h"
36 #include <math_support.h>
37 #include "sh_css_internal.h"
38 #include "input_formatter.h"
39 #include "assert_support.h"
40 #include "sh_css_sp.h"
41 #include "isp/modes/interface/input_buf.isp.h"
43 /************************************************************
44 * Static functions declarations
45 ************************************************************/
46 static enum ia_css_err ifmtr_start_column(
47 const struct ia_css_stream_config *config,
49 unsigned int *start_column);
51 static enum ia_css_err ifmtr_input_start_line(
52 const struct ia_css_stream_config *config,
54 unsigned int *start_line);
56 static void ifmtr_set_if_blocking_mode(
57 const input_formatter_cfg_t * const config_a,
58 const input_formatter_cfg_t * const config_b);
60 /************************************************************
62 ************************************************************/
64 /* ISP expects GRBG bayer order, we skip one line and/or one row
65 * to correct in case the input bayer order is different.
67 unsigned int ia_css_ifmtr_lines_needed_for_bayer_order(
68 const struct ia_css_stream_config *config)
70 assert(config != NULL);
71 if ((IA_CSS_BAYER_ORDER_BGGR == config->input_config.bayer_order)
72 || (IA_CSS_BAYER_ORDER_GBRG == config->input_config.bayer_order))
78 unsigned int ia_css_ifmtr_columns_needed_for_bayer_order(
79 const struct ia_css_stream_config *config)
81 assert(config != NULL);
82 if ((IA_CSS_BAYER_ORDER_RGGB == config->input_config.bayer_order)
83 || (IA_CSS_BAYER_ORDER_GBRG == config->input_config.bayer_order))
89 enum ia_css_err ia_css_ifmtr_configure(struct ia_css_stream_config *config,
90 struct ia_css_binary *binary)
92 unsigned int start_line, start_column = 0,
101 deinterleaving_b = 0,
106 vectors_per_line = 0,
107 buffers_per_line = 0,
111 width_b_factor = 1, start_column_b,
113 input_formatter_cfg_t if_a_config, if_b_config;
114 enum ia_css_stream_format input_format;
115 enum ia_css_err err = IA_CSS_SUCCESS;
116 uint8_t if_config_index;
118 /* Determine which input formatter config set is targeted. */
119 /* Index is equal to the CSI-2 port used. */
120 enum ia_css_csi2_port port;
123 cropped_height = binary->in_frame_info.res.height;
124 cropped_width = binary->in_frame_info.res.width;
125 /* This should correspond to the input buffer definition for
126 ISP binaries in input_buf.isp.h */
127 if (binary->info->sp.enable.continuous && binary->info->sp.pipeline.mode != IA_CSS_BINARY_MODE_COPY)
128 buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
130 buffer_width = binary->info->sp.input.max_width;
131 input_format = binary->input_format;
133 /* sp raw copy pipe (IA_CSS_PIPE_MODE_COPY): binary is NULL */
134 cropped_height = config->input_config.input_res.height;
135 cropped_width = config->input_config.input_res.width;
136 buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
137 input_format = config->input_config.format;
139 two_ppc = config->pixels_per_clock == 2;
140 if (config->mode == IA_CSS_INPUT_MODE_SENSOR
141 || config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
142 port = config->source.port.port;
143 if_config_index = (uint8_t) (port - IA_CSS_CSI2_PORT0);
144 } else if (config->mode == IA_CSS_INPUT_MODE_MEMORY) {
145 if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED;
150 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS
151 || if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED);
153 /* TODO: check to see if input is RAW and if current mode interprets
154 * RAW data in any particular bayer order. copy binary with output
155 * format other than raw should not result in dropping lines and/or
158 err = ifmtr_input_start_line(config, cropped_height, &start_line);
159 if (err != IA_CSS_SUCCESS)
161 err = ifmtr_start_column(config, cropped_width, &start_column);
162 if (err != IA_CSS_SUCCESS)
165 if (config->left_padding == -1)
167 /* sp raw copy pipe: set left_padding value */
170 left_padding = binary->left_padding;
172 left_padding = 2*ISP_VEC_NELEMS - config->left_padding;
176 num_vectors = CEIL_DIV(cropped_width + left_padding,
179 num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
180 num_vectors *= buffer_height;
181 /* todo: in case of left padding,
182 num_vectors is vectors per line,
183 otherwise vectors per line * buffer_height. */
186 start_column_b = start_column;
188 bits_per_pixel = input_formatter_get_alignment(INPUT_FORMATTER0_ID)
189 * 8 / ISP_VEC_NELEMS;
190 switch (input_format) {
191 case IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY:
195 deinterleaving_b = 1;
197 width_a = cropped_width * deinterleaving / 2;
200 width_b = width_a * width_b_factor;
201 buffer_width *= deinterleaving * 2;
202 /* Patch from bayer to yuv */
203 num_vectors *= deinterleaving;
204 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
205 vectors_per_line = num_vectors / buffer_height;
206 /* Even lines are half size */
207 line_width = vectors_per_line *
208 input_formatter_get_alignment(INPUT_FORMATTER0_ID) /
214 width_a = cropped_width * deinterleaving / 2;
215 buffer_width = buffer_width * deinterleaving / 2;
216 /* Patch from bayer to yuv */
217 num_vectors = num_vectors / 2 * deinterleaving;
218 start_column = start_column * deinterleaving / 2;
221 case IA_CSS_STREAM_FORMAT_YUV420_8:
222 case IA_CSS_STREAM_FORMAT_YUV420_10:
223 case IA_CSS_STREAM_FORMAT_YUV420_16:
227 width_a = width_b = cropped_width * deinterleaving / 2;
228 buffer_width *= deinterleaving * 2;
229 num_vectors *= deinterleaving;
230 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
231 vectors_per_line = num_vectors / buffer_height;
232 /* Even lines are half size */
233 line_width = vectors_per_line *
234 input_formatter_get_alignment(INPUT_FORMATTER0_ID) /
236 start_column *= deinterleaving;
238 start_column_b = start_column;
242 width_a = cropped_width * deinterleaving;
243 buffer_width *= deinterleaving * 2;
244 num_vectors *= deinterleaving;
245 start_column *= deinterleaving;
248 case IA_CSS_STREAM_FORMAT_YUV422_8:
249 case IA_CSS_STREAM_FORMAT_YUV422_10:
250 case IA_CSS_STREAM_FORMAT_YUV422_16:
254 width_a = width_b = cropped_width * deinterleaving;
255 buffer_width *= deinterleaving * 2;
256 num_vectors *= deinterleaving;
257 start_column *= deinterleaving;
258 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
259 start_column_b = start_column;
263 width_a = cropped_width * deinterleaving;
264 buffer_width *= deinterleaving;
265 num_vectors *= deinterleaving;
266 start_column *= deinterleaving;
269 case IA_CSS_STREAM_FORMAT_RGB_444:
270 case IA_CSS_STREAM_FORMAT_RGB_555:
271 case IA_CSS_STREAM_FORMAT_RGB_565:
272 case IA_CSS_STREAM_FORMAT_RGB_666:
273 case IA_CSS_STREAM_FORMAT_RGB_888:
276 deinterleaving = 2; /* BR in if_a, G in if_b */
277 deinterleaving_b = 1; /* BR in if_a, G in if_b */
278 buffers_per_line = 4;
279 start_column_b = start_column;
280 start_column *= deinterleaving;
281 start_column_b *= deinterleaving_b;
283 deinterleaving = 3; /* BGR */
284 buffers_per_line = 3;
285 start_column *= deinterleaving;
288 width_a = cropped_width * deinterleaving;
289 width_b = cropped_width * deinterleaving_b;
290 buffer_width *= buffers_per_line;
291 /* Patch from bayer to rgb */
292 num_vectors = num_vectors / 2 * deinterleaving;
293 buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
295 case IA_CSS_STREAM_FORMAT_RAW_6:
296 case IA_CSS_STREAM_FORMAT_RAW_7:
297 case IA_CSS_STREAM_FORMAT_RAW_8:
298 case IA_CSS_STREAM_FORMAT_RAW_10:
299 case IA_CSS_STREAM_FORMAT_RAW_12:
301 int crop_col = (start_column % 2) == 1;
304 width_a = width_b = cropped_width / 2;
306 /* When two_ppc is enabled AND we need to crop one extra
307 * column, if_a crops by one extra and we swap the
308 * output offsets to interleave the bayer pattern in
311 buf_offset_a = crop_col ? 1 : 0;
312 buf_offset_b = crop_col ? 0 : 1;
313 start_column_b = start_column / 2;
314 start_column = start_column / 2 + crop_col;
318 if ((!binary) || (config->continuous && binary
319 && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)) {
320 /* !binary -> sp raw copy pipe, no deinterleaving */
323 width_a = cropped_width;
324 /* Must be multiple of deinterleaving */
325 num_vectors = CEIL_MUL(num_vectors, deinterleaving);
328 if ((!binary) || config->continuous)
329 /* !binary -> sp raw copy pipe */
331 vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
332 vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving);
334 case IA_CSS_STREAM_FORMAT_RAW_14:
335 case IA_CSS_STREAM_FORMAT_RAW_16:
340 width_a = width_b = cropped_width;
341 /* B buffer is one line further */
342 buf_offset_b = buffer_width / ISP_VEC_NELEMS;
347 width_a = cropped_width;
348 start_column /= deinterleaving;
352 case IA_CSS_STREAM_FORMAT_BINARY_8:
353 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT1:
354 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT2:
355 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT3:
356 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT4:
357 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT5:
358 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT6:
359 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT7:
360 case IA_CSS_STREAM_FORMAT_GENERIC_SHORT8:
361 case IA_CSS_STREAM_FORMAT_YUV420_8_SHIFT:
362 case IA_CSS_STREAM_FORMAT_YUV420_10_SHIFT:
363 case IA_CSS_STREAM_FORMAT_EMBEDDED:
364 case IA_CSS_STREAM_FORMAT_USER_DEF1:
365 case IA_CSS_STREAM_FORMAT_USER_DEF2:
366 case IA_CSS_STREAM_FORMAT_USER_DEF3:
367 case IA_CSS_STREAM_FORMAT_USER_DEF4:
368 case IA_CSS_STREAM_FORMAT_USER_DEF5:
369 case IA_CSS_STREAM_FORMAT_USER_DEF6:
370 case IA_CSS_STREAM_FORMAT_USER_DEF7:
371 case IA_CSS_STREAM_FORMAT_USER_DEF8:
375 return IA_CSS_ERR_INVALID_ARGUMENTS;
382 vectors_per_line = num_vectors;
383 if (!vectors_per_line) {
384 vectors_per_line = CEIL_MUL(num_vectors / buffer_height,
389 line_width = vectors_per_line *
390 input_formatter_get_alignment(INPUT_FORMATTER0_ID);
391 if (!buffers_per_line)
392 buffers_per_line = deinterleaving;
393 line_width = CEIL_MUL(line_width,
394 input_formatter_get_alignment(INPUT_FORMATTER0_ID)
397 vectors_per_buffer = buffer_height * buffer_width / ISP_VEC_NELEMS;
399 if (config->mode == IA_CSS_INPUT_MODE_TPG &&
400 ((binary && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO) ||
402 /* !binary -> sp raw copy pipe */
403 /* workaround for TPG in video mode */
406 cropped_height -= start_line;
407 width_a -= start_column;
410 if_a_config.start_line = start_line;
411 if_a_config.start_column = start_column;
412 if_a_config.left_padding = left_padding / deinterleaving;
413 if_a_config.cropped_height = cropped_height;
414 if_a_config.cropped_width = width_a;
415 if_a_config.deinterleaving = deinterleaving;
416 if_a_config.buf_vecs = vectors_per_buffer;
417 if_a_config.buf_start_index = buf_offset_a;
418 if_a_config.buf_increment = vmem_increment;
419 if_a_config.buf_eol_offset =
420 buffer_width * bits_per_pixel / 8 - line_width;
421 if_a_config.is_yuv420_format =
422 (input_format == IA_CSS_STREAM_FORMAT_YUV420_8)
423 || (input_format == IA_CSS_STREAM_FORMAT_YUV420_10)
424 || (input_format == IA_CSS_STREAM_FORMAT_YUV420_16);
425 if_a_config.block_no_reqs = (config->mode != IA_CSS_INPUT_MODE_SENSOR);
428 if (deinterleaving_b) {
429 deinterleaving = deinterleaving_b;
430 width_b = cropped_width * deinterleaving;
431 buffer_width *= deinterleaving;
432 /* Patch from bayer to rgb */
433 num_vectors = num_vectors / 2 *
434 deinterleaving * width_b_factor;
435 vectors_per_line = num_vectors / buffer_height;
436 line_width = vectors_per_line *
437 input_formatter_get_alignment(INPUT_FORMATTER0_ID);
439 if_b_config.start_line = start_line;
440 if_b_config.start_column = start_column_b;
441 if_b_config.left_padding = left_padding / deinterleaving;
442 if_b_config.cropped_height = cropped_height;
443 if_b_config.cropped_width = width_b;
444 if_b_config.deinterleaving = deinterleaving;
445 if_b_config.buf_vecs = vectors_per_buffer;
446 if_b_config.buf_start_index = buf_offset_b;
447 if_b_config.buf_increment = vmem_increment;
448 if_b_config.buf_eol_offset =
449 buffer_width * bits_per_pixel / 8 - line_width;
450 if_b_config.is_yuv420_format =
451 input_format == IA_CSS_STREAM_FORMAT_YUV420_8
452 || input_format == IA_CSS_STREAM_FORMAT_YUV420_10
453 || input_format == IA_CSS_STREAM_FORMAT_YUV420_16;
454 if_b_config.block_no_reqs =
455 (config->mode != IA_CSS_INPUT_MODE_SENSOR);
457 if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) {
458 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
460 ifmtr_set_if_blocking_mode(&if_a_config, &if_b_config);
461 /* Set the ifconfigs to SP group */
462 sh_css_sp_set_if_configs(&if_a_config, &if_b_config,
466 if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) {
467 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
469 ifmtr_set_if_blocking_mode(&if_a_config, NULL);
470 /* Set the ifconfigs to SP group */
471 sh_css_sp_set_if_configs(&if_a_config, NULL,
476 return IA_CSS_SUCCESS;
479 bool ifmtr_set_if_blocking_mode_reset = true;
481 /************************************************************
483 ************************************************************/
484 static void ifmtr_set_if_blocking_mode(
485 const input_formatter_cfg_t * const config_a,
486 const input_formatter_cfg_t * const config_b)
489 bool block[] = { false, false, false, false };
490 assert(N_INPUT_FORMATTER_ID <= (sizeof(block) / sizeof(block[0])));
492 #if !defined(IS_ISP_2400_SYSTEM)
493 #error "ifmtr_set_if_blocking_mode: ISP_SYSTEM must be one of {IS_ISP_2400_SYSTEM}"
496 block[INPUT_FORMATTER0_ID] = (bool)config_a->block_no_reqs;
497 if (NULL != config_b)
498 block[INPUT_FORMATTER1_ID] = (bool)config_b->block_no_reqs;
500 /* TODO: next could cause issues when streams are started after
502 /*IF should not be reconfigured/reset from host */
503 if (ifmtr_set_if_blocking_mode_reset) {
504 ifmtr_set_if_blocking_mode_reset = false;
505 for (i = 0; i < N_INPUT_FORMATTER_ID; i++) {
506 input_formatter_ID_t id = (input_formatter_ID_t) i;
507 input_formatter_rst(id);
508 input_formatter_set_fifo_blocking_mode(id, block[id]);
515 static enum ia_css_err ifmtr_start_column(
516 const struct ia_css_stream_config *config,
518 unsigned int *start_column)
520 unsigned int in = config->input_config.input_res.width, start,
521 for_bayer = ia_css_ifmtr_columns_needed_for_bayer_order(config);
523 if (bin_in + 2 * for_bayer > in)
524 return IA_CSS_ERR_INVALID_ARGUMENTS;
526 /* On the hardware, we want to use the middle of the input, so we
527 * divide the start column by 2. */
528 start = (in - bin_in) / 2;
529 /* in case the number of extra columns is 2 or odd, we round the start
533 /* now we add the one column (if needed) to correct for the bayer
537 *start_column = start;
538 return IA_CSS_SUCCESS;
541 static enum ia_css_err ifmtr_input_start_line(
542 const struct ia_css_stream_config *config,
544 unsigned int *start_line)
546 unsigned int in = config->input_config.input_res.height, start,
547 for_bayer = ia_css_ifmtr_lines_needed_for_bayer_order(config);
549 if (bin_in + 2 * for_bayer > in)
550 return IA_CSS_ERR_INVALID_ARGUMENTS;
552 /* On the hardware, we want to use the middle of the input, so we
553 * divide the start line by 2. On the simulator, we cannot handle extra
554 * lines at the end of the frame.
556 start = (in - bin_in) / 2;
557 /* in case the number of extra lines is 2 or odd, we round the start
562 /* now we add the one line (if needed) to correct for the bayer order */
565 return IA_CSS_SUCCESS;