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"
32 #include <linux/kernel.h>
34 #ifdef USE_INPUT_SYSTEM_VERSION_2
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"
44 /************************************************************
45 * Static functions declarations
46 ************************************************************/
47 static enum ia_css_err ifmtr_start_column(
48 const struct ia_css_stream_config *config,
50 unsigned int *start_column);
52 static enum ia_css_err ifmtr_input_start_line(
53 const struct ia_css_stream_config *config,
55 unsigned int *start_line);
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);
61 /************************************************************
63 ************************************************************/
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.
68 unsigned int ia_css_ifmtr_lines_needed_for_bayer_order(
69 const struct ia_css_stream_config *config)
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))
79 unsigned int ia_css_ifmtr_columns_needed_for_bayer_order(
80 const struct ia_css_stream_config *config)
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))
90 enum ia_css_err ia_css_ifmtr_configure(struct ia_css_stream_config *config,
91 struct ia_css_binary *binary)
93 unsigned int start_line, start_column = 0,
102 deinterleaving_b = 0,
107 vectors_per_line = 0,
108 buffers_per_line = 0,
112 width_b_factor = 1, start_column_b,
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;
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;
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;
131 buffer_width = binary->info->sp.input.max_width;
132 input_format = binary->input_format;
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;
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;
151 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS
152 || if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED);
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
159 err = ifmtr_input_start_line(config, cropped_height, &start_line);
160 if (err != IA_CSS_SUCCESS)
162 err = ifmtr_start_column(config, cropped_width, &start_column);
163 if (err != IA_CSS_SUCCESS)
166 if (config->left_padding == -1)
168 /* sp raw copy pipe: set left_padding value */
171 left_padding = binary->left_padding;
173 left_padding = 2*ISP_VEC_NELEMS - config->left_padding;
177 num_vectors = CEIL_DIV(cropped_width + left_padding,
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. */
187 start_column_b = start_column;
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:
196 deinterleaving_b = 1;
198 width_a = cropped_width * deinterleaving / 2;
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) /
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;
222 case IA_CSS_STREAM_FORMAT_YUV420_8:
223 case IA_CSS_STREAM_FORMAT_YUV420_10:
224 case IA_CSS_STREAM_FORMAT_YUV420_16:
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) /
237 start_column *= deinterleaving;
239 start_column_b = start_column;
243 width_a = cropped_width * deinterleaving;
244 buffer_width *= deinterleaving * 2;
245 num_vectors *= deinterleaving;
246 start_column *= deinterleaving;
249 case IA_CSS_STREAM_FORMAT_YUV422_8:
250 case IA_CSS_STREAM_FORMAT_YUV422_10:
251 case IA_CSS_STREAM_FORMAT_YUV422_16:
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;
264 width_a = cropped_width * deinterleaving;
265 buffer_width *= deinterleaving;
266 num_vectors *= deinterleaving;
267 start_column *= deinterleaving;
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:
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;
284 deinterleaving = 3; /* BGR */
285 buffers_per_line = 3;
286 start_column *= deinterleaving;
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;
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:
302 int crop_col = (start_column % 2) == 1;
305 width_a = width_b = cropped_width / 2;
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
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;
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 */
324 width_a = cropped_width;
325 /* Must be multiple of deinterleaving */
326 num_vectors = CEIL_MUL(num_vectors, deinterleaving);
329 if ((!binary) || config->continuous)
330 /* !binary -> sp raw copy pipe */
332 vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
333 vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving);
335 case IA_CSS_STREAM_FORMAT_RAW_14:
336 case IA_CSS_STREAM_FORMAT_RAW_16:
341 width_a = width_b = cropped_width;
342 /* B buffer is one line further */
343 buf_offset_b = buffer_width / ISP_VEC_NELEMS;
348 width_a = cropped_width;
349 start_column /= deinterleaving;
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:
376 return IA_CSS_ERR_INVALID_ARGUMENTS;
383 vectors_per_line = num_vectors;
384 if (!vectors_per_line) {
385 vectors_per_line = CEIL_MUL(num_vectors / buffer_height,
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)
398 vectors_per_buffer = buffer_height * buffer_width / ISP_VEC_NELEMS;
400 if (config->mode == IA_CSS_INPUT_MODE_TPG &&
401 ((binary && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO) ||
403 /* !binary -> sp raw copy pipe */
404 /* workaround for TPG in video mode */
407 cropped_height -= start_line;
408 width_a -= start_column;
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);
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);
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);
458 if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) {
459 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
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,
467 if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) {
468 assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
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,
477 return IA_CSS_SUCCESS;
480 bool ifmtr_set_if_blocking_mode_reset = true;
482 /************************************************************
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)
490 bool block[] = { false, false, false, false };
491 assert(N_INPUT_FORMATTER_ID <= (ARRAY_SIZE(block)));
493 #if !defined(IS_ISP_2400_SYSTEM)
494 #error "ifmtr_set_if_blocking_mode: ISP_SYSTEM must be one of {IS_ISP_2400_SYSTEM}"
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;
501 /* TODO: next could cause issues when streams are started after
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]);
516 static enum ia_css_err ifmtr_start_column(
517 const struct ia_css_stream_config *config,
519 unsigned int *start_column)
521 unsigned int in = config->input_config.input_res.width, start,
522 for_bayer = ia_css_ifmtr_columns_needed_for_bayer_order(config);
524 if (bin_in + 2 * for_bayer > in)
525 return IA_CSS_ERR_INVALID_ARGUMENTS;
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
534 /* now we add the one column (if needed) to correct for the bayer
538 *start_column = start;
539 return IA_CSS_SUCCESS;
542 static enum ia_css_err ifmtr_input_start_line(
543 const struct ia_css_stream_config *config,
545 unsigned int *start_line)
547 unsigned int in = config->input_config.input_res.height, start,
548 for_bayer = ia_css_ifmtr_lines_needed_for_bayer_order(config);
550 if (bin_in + 2 * for_bayer > in)
551 return IA_CSS_ERR_INVALID_ARGUMENTS;
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.
557 start = (in - bin_in) / 2;
558 /* in case the number of extra lines is 2 or odd, we round the start
563 /* now we add the one line (if needed) to correct for the bayer order */
566 return IA_CSS_SUCCESS;