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