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