ipu3-css-params.c (95403B)
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (C) 2018 Intel Corporation 3 4#include <linux/device.h> 5 6#include "ipu3-css.h" 7#include "ipu3-css-fw.h" 8#include "ipu3-tables.h" 9#include "ipu3-css-params.h" 10 11#define DIV_ROUND_CLOSEST_DOWN(a, b) (((a) + ((b) / 2) - 1) / (b)) 12#define roundclosest_down(a, b) (DIV_ROUND_CLOSEST_DOWN(a, b) * (b)) 13 14#define IPU3_UAPI_ANR_MAX_RESET ((1 << 12) - 1) 15#define IPU3_UAPI_ANR_MIN_RESET (((-1) << 12) + 1) 16 17struct imgu_css_scaler_info { 18 unsigned int phase_step; /* Same for luma/chroma */ 19 int exp_shift; 20 21 unsigned int phase_init; /* luma/chroma dependent */ 22 int pad_left; 23 int pad_right; 24 int crop_left; 25 int crop_top; 26}; 27 28static unsigned int imgu_css_scaler_get_exp(unsigned int counter, 29 unsigned int divider) 30{ 31 int i = fls(divider) - fls(counter); 32 33 if (i <= 0) 34 return 0; 35 36 if (divider >> i < counter) 37 i = i - 1; 38 39 return i; 40} 41 42/* Set up the CSS scaler look up table */ 43static void 44imgu_css_scaler_setup_lut(unsigned int taps, unsigned int input_width, 45 unsigned int output_width, int phase_step_correction, 46 const int *coeffs, unsigned int coeffs_size, 47 s8 coeff_lut[], struct imgu_css_scaler_info *info) 48{ 49 int tap, phase, phase_sum_left, phase_sum_right; 50 int exponent = imgu_css_scaler_get_exp(output_width, input_width); 51 int mantissa = (1 << exponent) * output_width; 52 unsigned int phase_step, phase_taps; 53 54 if (input_width == output_width) { 55 for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) { 56 phase_taps = phase * IMGU_SCALER_FILTER_TAPS; 57 for (tap = 0; tap < taps; tap++) 58 coeff_lut[phase_taps + tap] = 0; 59 } 60 61 info->phase_step = IMGU_SCALER_PHASES * 62 (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF); 63 info->exp_shift = 0; 64 info->pad_left = 0; 65 info->pad_right = 0; 66 info->phase_init = 0; 67 info->crop_left = 0; 68 info->crop_top = 0; 69 return; 70 } 71 72 for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) { 73 phase_taps = phase * IMGU_SCALER_FILTER_TAPS; 74 for (tap = 0; tap < taps; tap++) { 75 /* flip table to for convolution reverse indexing */ 76 s64 coeff = coeffs[coeffs_size - 77 ((tap * (coeffs_size / taps)) + phase) - 1]; 78 coeff *= mantissa; 79 coeff = div64_long(coeff, input_width); 80 81 /* Add +"0.5" */ 82 coeff += 1 << (IMGU_SCALER_COEFF_BITS - 1); 83 coeff >>= IMGU_SCALER_COEFF_BITS; 84 coeff_lut[phase_taps + tap] = coeff; 85 } 86 } 87 88 phase_step = IMGU_SCALER_PHASES * 89 (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF) * 90 output_width / input_width; 91 phase_step += phase_step_correction; 92 phase_sum_left = (taps / 2 * IMGU_SCALER_PHASES * 93 (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) - 94 (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1)); 95 phase_sum_right = (taps / 2 * IMGU_SCALER_PHASES * 96 (1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)) + 97 (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1)); 98 99 info->exp_shift = IMGU_SCALER_MAX_EXPONENT_SHIFT - exponent; 100 info->pad_left = (phase_sum_left % phase_step == 0) ? 101 phase_sum_left / phase_step - 1 : phase_sum_left / phase_step; 102 info->pad_right = (phase_sum_right % phase_step == 0) ? 103 phase_sum_right / phase_step - 1 : phase_sum_right / phase_step; 104 info->phase_init = phase_sum_left - phase_step * info->pad_left; 105 info->phase_step = phase_step; 106 info->crop_left = taps - 1; 107 info->crop_top = taps - 1; 108} 109 110/* 111 * Calculates the exact output image width/height, based on phase_step setting 112 * (must be perfectly aligned with hardware). 113 */ 114static unsigned int 115imgu_css_scaler_calc_scaled_output(unsigned int input, 116 struct imgu_css_scaler_info *info) 117{ 118 unsigned int arg1 = input * info->phase_step + 119 (1 - IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES - 120 IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES); 121 unsigned int arg2 = ((IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES + 122 IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES)) * 123 IMGU_SCALER_FIR_PHASES + info->phase_step / 2; 124 125 return ((arg1 + (arg2 - IMGU_SCALER_FIR_PHASES * info->phase_step) / 126 IMGU_SCALER_FIR_PHASES) / (2 * IMGU_SCALER_FIR_PHASES)) * 2; 127} 128 129/* 130 * Calculate the output width and height, given the luma 131 * and chroma details of a scaler 132 */ 133static void 134imgu_css_scaler_calc(u32 input_width, u32 input_height, u32 target_width, 135 u32 target_height, struct imgu_abi_osys_config *cfg, 136 struct imgu_css_scaler_info *info_luma, 137 struct imgu_css_scaler_info *info_chroma, 138 unsigned int *output_width, unsigned int *output_height, 139 unsigned int *procmode) 140{ 141 u32 out_width = target_width; 142 u32 out_height = target_height; 143 const unsigned int height_alignment = 2; 144 int phase_step_correction = -1; 145 146 /* 147 * Calculate scaled output width. If the horizontal and vertical scaling 148 * factor is different, then choose the biggest and crop off excess 149 * lines or columns after formatting. 150 */ 151 if (target_height * input_width > target_width * input_height) 152 target_width = DIV_ROUND_UP(target_height * input_width, 153 input_height); 154 155 if (input_width == target_width) 156 *procmode = IMGU_ABI_OSYS_PROCMODE_BYPASS; 157 else 158 *procmode = IMGU_ABI_OSYS_PROCMODE_DOWNSCALE; 159 160 memset(&cfg->scaler_coeffs_chroma, 0, 161 sizeof(cfg->scaler_coeffs_chroma)); 162 memset(&cfg->scaler_coeffs_luma, 0, sizeof(cfg->scaler_coeffs_luma)); 163 do { 164 phase_step_correction++; 165 166 imgu_css_scaler_setup_lut(IMGU_SCALER_TAPS_Y, 167 input_width, target_width, 168 phase_step_correction, 169 imgu_css_downscale_4taps, 170 IMGU_SCALER_DOWNSCALE_4TAPS_LEN, 171 cfg->scaler_coeffs_luma, info_luma); 172 173 imgu_css_scaler_setup_lut(IMGU_SCALER_TAPS_UV, 174 input_width, target_width, 175 phase_step_correction, 176 imgu_css_downscale_2taps, 177 IMGU_SCALER_DOWNSCALE_2TAPS_LEN, 178 cfg->scaler_coeffs_chroma, 179 info_chroma); 180 181 out_width = imgu_css_scaler_calc_scaled_output(input_width, 182 info_luma); 183 out_height = imgu_css_scaler_calc_scaled_output(input_height, 184 info_luma); 185 } while ((out_width < target_width || out_height < target_height || 186 !IS_ALIGNED(out_height, height_alignment)) && 187 phase_step_correction <= 5); 188 189 *output_width = out_width; 190 *output_height = out_height; 191} 192 193/********************** Osys routines for scaler****************************/ 194 195static void imgu_css_osys_set_format(enum imgu_abi_frame_format host_format, 196 unsigned int *osys_format, 197 unsigned int *osys_tiling) 198{ 199 *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420; 200 *osys_tiling = IMGU_ABI_OSYS_TILING_NONE; 201 202 switch (host_format) { 203 case IMGU_ABI_FRAME_FORMAT_YUV420: 204 *osys_format = IMGU_ABI_OSYS_FORMAT_YUV420; 205 break; 206 case IMGU_ABI_FRAME_FORMAT_YV12: 207 *osys_format = IMGU_ABI_OSYS_FORMAT_YV12; 208 break; 209 case IMGU_ABI_FRAME_FORMAT_NV12: 210 *osys_format = IMGU_ABI_OSYS_FORMAT_NV12; 211 break; 212 case IMGU_ABI_FRAME_FORMAT_NV16: 213 *osys_format = IMGU_ABI_OSYS_FORMAT_NV16; 214 break; 215 case IMGU_ABI_FRAME_FORMAT_NV21: 216 *osys_format = IMGU_ABI_OSYS_FORMAT_NV21; 217 break; 218 case IMGU_ABI_FRAME_FORMAT_NV12_TILEY: 219 *osys_format = IMGU_ABI_OSYS_FORMAT_NV12; 220 *osys_tiling = IMGU_ABI_OSYS_TILING_Y; 221 break; 222 default: 223 /* For now, assume use default values */ 224 break; 225 } 226} 227 228/* 229 * Function calculates input frame stripe offset, based 230 * on output frame stripe offset and filter parameters. 231 */ 232static int imgu_css_osys_calc_stripe_offset(int stripe_offset_out, 233 int fir_phases, int phase_init, 234 int phase_step, int pad_left) 235{ 236 int stripe_offset_inp = stripe_offset_out * fir_phases - 237 pad_left * phase_step; 238 239 return DIV_ROUND_UP(stripe_offset_inp - phase_init, phase_step); 240} 241 242/* 243 * Calculate input frame phase, given the output frame 244 * stripe offset and filter parameters 245 */ 246static int imgu_css_osys_calc_stripe_phase_init(int stripe_offset_out, 247 int fir_phases, int phase_init, 248 int phase_step, int pad_left) 249{ 250 int stripe_offset_inp = 251 imgu_css_osys_calc_stripe_offset(stripe_offset_out, 252 fir_phases, phase_init, 253 phase_step, pad_left); 254 255 return phase_init + ((pad_left + stripe_offset_inp) * phase_step) - 256 stripe_offset_out * fir_phases; 257} 258 259/* 260 * This function calculates input frame stripe width, 261 * based on output frame stripe offset and filter parameters 262 */ 263static int imgu_css_osys_calc_inp_stripe_width(int stripe_width_out, 264 int fir_phases, int phase_init, 265 int phase_step, int fir_taps, 266 int pad_left, int pad_right) 267{ 268 int stripe_width_inp = (stripe_width_out + fir_taps - 1) * fir_phases; 269 270 stripe_width_inp = DIV_ROUND_UP(stripe_width_inp - phase_init, 271 phase_step); 272 273 return stripe_width_inp - pad_left - pad_right; 274} 275 276/* 277 * This function calculates output frame stripe width, basedi 278 * on output frame stripe offset and filter parameters 279 */ 280static int imgu_css_osys_out_stripe_width(int stripe_width_inp, int fir_phases, 281 int phase_init, int phase_step, 282 int fir_taps, int pad_left, 283 int pad_right, int column_offset) 284{ 285 int stripe_width_out = (pad_left + stripe_width_inp + 286 pad_right - column_offset) * phase_step; 287 288 stripe_width_out = (stripe_width_out + phase_init) / fir_phases; 289 290 return stripe_width_out - (fir_taps - 1); 291} 292 293struct imgu_css_reso { 294 unsigned int input_width; 295 unsigned int input_height; 296 enum imgu_abi_frame_format input_format; 297 unsigned int pin_width[IMGU_ABI_OSYS_PINS]; 298 unsigned int pin_height[IMGU_ABI_OSYS_PINS]; 299 unsigned int pin_stride[IMGU_ABI_OSYS_PINS]; 300 enum imgu_abi_frame_format pin_format[IMGU_ABI_OSYS_PINS]; 301 int chunk_width; 302 int chunk_height; 303 int block_height; 304 int block_width; 305}; 306 307struct imgu_css_frame_params { 308 /* Output pins */ 309 unsigned int enable; 310 unsigned int format; 311 unsigned int flip; 312 unsigned int mirror; 313 unsigned int tiling; 314 unsigned int reduce_range; 315 unsigned int width; 316 unsigned int height; 317 unsigned int stride; 318 unsigned int scaled; 319 unsigned int crop_left; 320 unsigned int crop_top; 321}; 322 323struct imgu_css_stripe_params { 324 unsigned int processing_mode; 325 unsigned int phase_step; 326 unsigned int exp_shift; 327 unsigned int phase_init_left_y; 328 unsigned int phase_init_left_uv; 329 unsigned int phase_init_top_y; 330 unsigned int phase_init_top_uv; 331 unsigned int pad_left_y; 332 unsigned int pad_left_uv; 333 unsigned int pad_right_y; 334 unsigned int pad_right_uv; 335 unsigned int pad_top_y; 336 unsigned int pad_top_uv; 337 unsigned int pad_bottom_y; 338 unsigned int pad_bottom_uv; 339 unsigned int crop_left_y; 340 unsigned int crop_top_y; 341 unsigned int crop_left_uv; 342 unsigned int crop_top_uv; 343 unsigned int start_column_y; 344 unsigned int start_column_uv; 345 unsigned int chunk_width; 346 unsigned int chunk_height; 347 unsigned int block_width; 348 unsigned int block_height; 349 unsigned int input_width; 350 unsigned int input_height; 351 int output_width[IMGU_ABI_OSYS_PINS]; 352 int output_height[IMGU_ABI_OSYS_PINS]; 353 int output_offset[IMGU_ABI_OSYS_PINS]; 354}; 355 356/* 357 * frame_params - size IMGU_ABI_OSYS_PINS 358 * stripe_params - size IPU3_UAPI_MAX_STRIPES 359 */ 360static int imgu_css_osys_calc_frame_and_stripe_params( 361 struct imgu_css *css, unsigned int stripes, 362 struct imgu_abi_osys_config *osys, 363 struct imgu_css_scaler_info *scaler_luma, 364 struct imgu_css_scaler_info *scaler_chroma, 365 struct imgu_css_frame_params frame_params[], 366 struct imgu_css_stripe_params stripe_params[], 367 unsigned int pipe) 368{ 369 struct imgu_css_reso reso; 370 unsigned int output_width, pin, s; 371 u32 input_width, input_height, target_width, target_height; 372 unsigned int procmode = 0; 373 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 374 375 input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width; 376 input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height; 377 target_width = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width; 378 target_height = css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height; 379 380 /* Frame parameters */ 381 382 /* Input width for Output System is output width of DVS (with GDC) */ 383 reso.input_width = css_pipe->rect[IPU3_CSS_RECT_GDC].width; 384 385 /* Input height for Output System is output height of DVS (with GDC) */ 386 reso.input_height = css_pipe->rect[IPU3_CSS_RECT_GDC].height; 387 388 reso.input_format = 389 css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format; 390 391 reso.pin_width[IMGU_ABI_OSYS_PIN_OUT] = 392 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width; 393 reso.pin_height[IMGU_ABI_OSYS_PIN_OUT] = 394 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 395 reso.pin_stride[IMGU_ABI_OSYS_PIN_OUT] = 396 css_pipe->queue[IPU3_CSS_QUEUE_OUT].width_pad; 397 reso.pin_format[IMGU_ABI_OSYS_PIN_OUT] = 398 css_pipe->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format; 399 400 reso.pin_width[IMGU_ABI_OSYS_PIN_VF] = 401 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width; 402 reso.pin_height[IMGU_ABI_OSYS_PIN_VF] = 403 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height; 404 reso.pin_stride[IMGU_ABI_OSYS_PIN_VF] = 405 css_pipe->queue[IPU3_CSS_QUEUE_VF].width_pad; 406 reso.pin_format[IMGU_ABI_OSYS_PIN_VF] = 407 css_pipe->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format; 408 409 /* Configure the frame parameters for all output pins */ 410 411 frame_params[IMGU_ABI_OSYS_PIN_OUT].width = 412 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width; 413 frame_params[IMGU_ABI_OSYS_PIN_OUT].height = 414 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 415 frame_params[IMGU_ABI_OSYS_PIN_VF].width = 416 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width; 417 frame_params[IMGU_ABI_OSYS_PIN_VF].height = 418 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height; 419 frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 0; 420 frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 0; 421 422 for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) { 423 int enable = 0; 424 int scaled = 0; 425 unsigned int format = 0; 426 unsigned int tiling = 0; 427 428 frame_params[pin].flip = 0; 429 frame_params[pin].mirror = 0; 430 frame_params[pin].reduce_range = 0; 431 if (reso.pin_width[pin] != 0 && reso.pin_height[pin] != 0) { 432 enable = 1; 433 if (pin == IMGU_ABI_OSYS_PIN_OUT) { 434 if (reso.input_width < reso.pin_width[pin] || 435 reso.input_height < reso.pin_height[pin]) 436 return -EINVAL; 437 /* 438 * When input and output resolution is 439 * different instead of scaling, cropping 440 * should happen. Determine the crop factor 441 * to do the symmetric cropping 442 */ 443 frame_params[pin].crop_left = roundclosest_down( 444 (reso.input_width - 445 reso.pin_width[pin]) / 2, 446 IMGU_OSYS_DMA_CROP_W_LIMIT); 447 frame_params[pin].crop_top = roundclosest_down( 448 (reso.input_height - 449 reso.pin_height[pin]) / 2, 450 IMGU_OSYS_DMA_CROP_H_LIMIT); 451 } else { 452 if (reso.pin_width[pin] != reso.input_width || 453 reso.pin_height[pin] != reso.input_height) { 454 /* 455 * If resolution is different at input 456 * and output of OSYS, scaling is 457 * considered except when pin is MAIN. 458 * Later it will be decide whether 459 * scaler factor is 1 or other 460 * and cropping has to be done or not. 461 */ 462 scaled = 1; 463 } 464 } 465 imgu_css_osys_set_format(reso.pin_format[pin], &format, 466 &tiling); 467 } else { 468 enable = 0; 469 } 470 frame_params[pin].enable = enable; 471 frame_params[pin].format = format; 472 frame_params[pin].tiling = tiling; 473 frame_params[pin].stride = reso.pin_stride[pin]; 474 frame_params[pin].scaled = scaled; 475 } 476 477 imgu_css_scaler_calc(input_width, input_height, target_width, 478 target_height, osys, scaler_luma, scaler_chroma, 479 &reso.pin_width[IMGU_ABI_OSYS_PIN_VF], 480 &reso.pin_height[IMGU_ABI_OSYS_PIN_VF], &procmode); 481 dev_dbg(css->dev, "osys scaler procmode is %u", procmode); 482 output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF]; 483 484 if (output_width < reso.input_width / 2) { 485 /* Scaling factor <= 0.5 */ 486 reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH; 487 reso.block_width = IMGU_OSYS_BLOCK_WIDTH; 488 } else { /* 0.5 <= Scaling factor <= 1.0 */ 489 reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH / 2; 490 reso.block_width = IMGU_OSYS_BLOCK_WIDTH; 491 } 492 493 if (output_width <= reso.input_width * 7 / 8) { 494 /* Scaling factor <= 0.875 */ 495 reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT; 496 reso.block_height = IMGU_OSYS_BLOCK_HEIGHT; 497 } else { /* 1.0 <= Scaling factor <= 1.75 */ 498 reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT / 2; 499 reso.block_height = IMGU_OSYS_BLOCK_HEIGHT; 500 } 501 502 /* 503 * Calculate scaler configuration parameters based on input and output 504 * resolution. 505 */ 506 507 if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) { 508 /* 509 * When aspect ratio is different between target resolution and 510 * required resolution, determine the crop factor to do 511 * symmetric cropping 512 */ 513 u32 w = reso.pin_width[IMGU_ABI_OSYS_PIN_VF] - 514 frame_params[IMGU_ABI_OSYS_PIN_VF].width; 515 u32 h = reso.pin_height[IMGU_ABI_OSYS_PIN_VF] - 516 frame_params[IMGU_ABI_OSYS_PIN_VF].height; 517 518 frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 519 roundclosest_down(w / 2, IMGU_OSYS_DMA_CROP_W_LIMIT); 520 frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 521 roundclosest_down(h / 2, IMGU_OSYS_DMA_CROP_H_LIMIT); 522 523 if (reso.input_height % 4 || reso.input_width % 8) { 524 dev_err(css->dev, "OSYS input width is not multiple of 8 or\n"); 525 dev_err(css->dev, "height is not multiple of 4\n"); 526 return -EINVAL; 527 } 528 } 529 530 /* Stripe parameters */ 531 532 if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) { 533 output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF]; 534 } else { 535 /* 536 * in case scaler output is not enabled 537 * take output width as input width since 538 * there is no scaling at main pin. 539 * Due to the fact that main pin can be different 540 * from input resolution to osys in the case of cropping, 541 * main pin resolution is not taken. 542 */ 543 output_width = reso.input_width; 544 } 545 546 for (s = 0; s < stripes; s++) { 547 int stripe_offset_inp_y = 0; 548 int stripe_offset_inp_uv = 0; 549 int stripe_offset_out_y = 0; 550 int stripe_offset_out_uv = 0; 551 int stripe_phase_init_y = scaler_luma->phase_init; 552 int stripe_phase_init_uv = scaler_chroma->phase_init; 553 int stripe_offset_blk_y = 0; 554 int stripe_offset_blk_uv = 0; 555 int stripe_offset_col_y = 0; 556 int stripe_offset_col_uv = 0; 557 int stripe_pad_left_y = scaler_luma->pad_left; 558 int stripe_pad_left_uv = scaler_chroma->pad_left; 559 int stripe_pad_right_y = scaler_luma->pad_right; 560 int stripe_pad_right_uv = scaler_chroma->pad_right; 561 int stripe_crop_left_y = scaler_luma->crop_left; 562 int stripe_crop_left_uv = scaler_chroma->crop_left; 563 int stripe_input_width_y = reso.input_width; 564 int stripe_input_width_uv = 0; 565 int stripe_output_width_y = output_width; 566 int stripe_output_width_uv = 0; 567 int chunk_floor_y = 0; 568 int chunk_floor_uv = 0; 569 int chunk_ceil_uv = 0; 570 571 if (stripes > 1) { 572 if (s > 0) { 573 /* Calculate stripe offsets */ 574 stripe_offset_out_y = 575 output_width * s / stripes; 576 stripe_offset_out_y = 577 rounddown(stripe_offset_out_y, 578 IPU3_UAPI_ISP_VEC_ELEMS); 579 stripe_offset_out_uv = stripe_offset_out_y / 580 IMGU_LUMA_TO_CHROMA_RATIO; 581 stripe_offset_inp_y = 582 imgu_css_osys_calc_stripe_offset( 583 stripe_offset_out_y, 584 IMGU_OSYS_FIR_PHASES, 585 scaler_luma->phase_init, 586 scaler_luma->phase_step, 587 scaler_luma->pad_left); 588 stripe_offset_inp_uv = 589 imgu_css_osys_calc_stripe_offset( 590 stripe_offset_out_uv, 591 IMGU_OSYS_FIR_PHASES, 592 scaler_chroma->phase_init, 593 scaler_chroma->phase_step, 594 scaler_chroma->pad_left); 595 596 /* Calculate stripe phase init */ 597 stripe_phase_init_y = 598 imgu_css_osys_calc_stripe_phase_init( 599 stripe_offset_out_y, 600 IMGU_OSYS_FIR_PHASES, 601 scaler_luma->phase_init, 602 scaler_luma->phase_step, 603 scaler_luma->pad_left); 604 stripe_phase_init_uv = 605 imgu_css_osys_calc_stripe_phase_init( 606 stripe_offset_out_uv, 607 IMGU_OSYS_FIR_PHASES, 608 scaler_chroma->phase_init, 609 scaler_chroma->phase_step, 610 scaler_chroma->pad_left); 611 612 /* 613 * Chunk boundary corner case - luma and chroma 614 * start from different input chunks. 615 */ 616 chunk_floor_y = rounddown(stripe_offset_inp_y, 617 reso.chunk_width); 618 chunk_floor_uv = 619 rounddown(stripe_offset_inp_uv, 620 reso.chunk_width / 621 IMGU_LUMA_TO_CHROMA_RATIO); 622 623 if (chunk_floor_y != chunk_floor_uv * 624 IMGU_LUMA_TO_CHROMA_RATIO) { 625 /* 626 * Match starting luma/chroma chunks. 627 * Decrease offset for UV and add output 628 * cropping. 629 */ 630 stripe_offset_inp_uv -= 1; 631 stripe_crop_left_uv += 1; 632 stripe_phase_init_uv -= 633 scaler_luma->phase_step; 634 if (stripe_phase_init_uv < 0) 635 stripe_phase_init_uv = 636 stripe_phase_init_uv + 637 IMGU_OSYS_FIR_PHASES; 638 } 639 /* 640 * FW workaround for a HW bug: if the first 641 * chroma pixel is generated exactly at the end 642 * of chunck scaler HW may not output the pixel 643 * for downscale factors smaller than 1.5 644 * (timing issue). 645 */ 646 chunk_ceil_uv = 647 roundup(stripe_offset_inp_uv, 648 reso.chunk_width / 649 IMGU_LUMA_TO_CHROMA_RATIO); 650 651 if (stripe_offset_inp_uv == 652 chunk_ceil_uv - IMGU_OSYS_TAPS_UV) { 653 /* 654 * Decrease input offset and add 655 * output cropping 656 */ 657 stripe_offset_inp_uv -= 1; 658 stripe_phase_init_uv -= 659 scaler_luma->phase_step; 660 if (stripe_phase_init_uv < 0) { 661 stripe_phase_init_uv += 662 IMGU_OSYS_FIR_PHASES; 663 stripe_crop_left_uv += 1; 664 } 665 } 666 667 /* 668 * Calculate block and column offsets for the 669 * input stripe 670 */ 671 stripe_offset_blk_y = 672 rounddown(stripe_offset_inp_y, 673 IMGU_INPUT_BLOCK_WIDTH); 674 stripe_offset_blk_uv = 675 rounddown(stripe_offset_inp_uv, 676 IMGU_INPUT_BLOCK_WIDTH / 677 IMGU_LUMA_TO_CHROMA_RATIO); 678 stripe_offset_col_y = stripe_offset_inp_y - 679 stripe_offset_blk_y; 680 stripe_offset_col_uv = stripe_offset_inp_uv - 681 stripe_offset_blk_uv; 682 683 /* Left padding is only for the first stripe */ 684 stripe_pad_left_y = 0; 685 stripe_pad_left_uv = 0; 686 } 687 688 /* Right padding is only for the last stripe */ 689 if (s < stripes - 1) { 690 int next_offset; 691 692 stripe_pad_right_y = 0; 693 stripe_pad_right_uv = 0; 694 695 next_offset = output_width * (s + 1) / stripes; 696 next_offset = rounddown(next_offset, 64); 697 stripe_output_width_y = next_offset - 698 stripe_offset_out_y; 699 } else { 700 stripe_output_width_y = output_width - 701 stripe_offset_out_y; 702 } 703 704 /* Calculate target output stripe width */ 705 stripe_output_width_uv = stripe_output_width_y / 706 IMGU_LUMA_TO_CHROMA_RATIO; 707 /* Calculate input stripe width */ 708 stripe_input_width_y = stripe_offset_col_y + 709 imgu_css_osys_calc_inp_stripe_width( 710 stripe_output_width_y, 711 IMGU_OSYS_FIR_PHASES, 712 stripe_phase_init_y, 713 scaler_luma->phase_step, 714 IMGU_OSYS_TAPS_Y, 715 stripe_pad_left_y, 716 stripe_pad_right_y); 717 718 stripe_input_width_uv = stripe_offset_col_uv + 719 imgu_css_osys_calc_inp_stripe_width( 720 stripe_output_width_uv, 721 IMGU_OSYS_FIR_PHASES, 722 stripe_phase_init_uv, 723 scaler_chroma->phase_step, 724 IMGU_OSYS_TAPS_UV, 725 stripe_pad_left_uv, 726 stripe_pad_right_uv); 727 728 stripe_input_width_uv = max(DIV_ROUND_UP( 729 stripe_input_width_y, 730 IMGU_LUMA_TO_CHROMA_RATIO), 731 stripe_input_width_uv); 732 733 stripe_input_width_y = stripe_input_width_uv * 734 IMGU_LUMA_TO_CHROMA_RATIO; 735 736 if (s >= stripes - 1) { 737 stripe_input_width_y = reso.input_width - 738 stripe_offset_blk_y; 739 /* 740 * The scaler requires that the last stripe 741 * spans at least two input blocks. 742 */ 743 } 744 745 /* 746 * Spec: input stripe width must be a multiple of 8. 747 * Increase the input width and recalculate the output 748 * width. This may produce an extra column of junk 749 * blocks which will be overwritten by the 750 * next stripe. 751 */ 752 stripe_input_width_y = ALIGN(stripe_input_width_y, 8); 753 stripe_output_width_y = 754 imgu_css_osys_out_stripe_width( 755 stripe_input_width_y, 756 IMGU_OSYS_FIR_PHASES, 757 stripe_phase_init_y, 758 scaler_luma->phase_step, 759 IMGU_OSYS_TAPS_Y, 760 stripe_pad_left_y, 761 stripe_pad_right_y, 762 stripe_offset_col_y); 763 764 stripe_output_width_y = 765 rounddown(stripe_output_width_y, 766 IMGU_LUMA_TO_CHROMA_RATIO); 767 } 768 /* 769 * Following section executes and process parameters 770 * for both cases - Striping or No Striping. 771 */ 772 { 773 unsigned int i; 774 /*Input resolution */ 775 776 stripe_params[s].input_width = stripe_input_width_y; 777 stripe_params[s].input_height = reso.input_height; 778 779 for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) { 780 if (frame_params[i].scaled) { 781 /* 782 * Output stripe resolution and offset 783 * as produced by the scaler; actual 784 * output resolution may be slightly 785 * smaller. 786 */ 787 stripe_params[s].output_width[i] = 788 stripe_output_width_y; 789 stripe_params[s].output_height[i] = 790 reso.pin_height[i]; 791 stripe_params[s].output_offset[i] = 792 stripe_offset_out_y; 793 } else { 794 /* Unscaled pin */ 795 stripe_params[s].output_width[i] = 796 stripe_params[s].input_width; 797 stripe_params[s].output_height[i] = 798 stripe_params[s].input_height; 799 stripe_params[s].output_offset[i] = 800 stripe_offset_blk_y; 801 } 802 } 803 804 /* If no pin use scale, we use BYPASS mode */ 805 stripe_params[s].processing_mode = procmode; 806 stripe_params[s].phase_step = scaler_luma->phase_step; 807 stripe_params[s].exp_shift = scaler_luma->exp_shift; 808 stripe_params[s].phase_init_left_y = 809 stripe_phase_init_y; 810 stripe_params[s].phase_init_left_uv = 811 stripe_phase_init_uv; 812 stripe_params[s].phase_init_top_y = 813 scaler_luma->phase_init; 814 stripe_params[s].phase_init_top_uv = 815 scaler_chroma->phase_init; 816 stripe_params[s].pad_left_y = stripe_pad_left_y; 817 stripe_params[s].pad_left_uv = stripe_pad_left_uv; 818 stripe_params[s].pad_right_y = stripe_pad_right_y; 819 stripe_params[s].pad_right_uv = stripe_pad_right_uv; 820 stripe_params[s].pad_top_y = scaler_luma->pad_left; 821 stripe_params[s].pad_top_uv = scaler_chroma->pad_left; 822 stripe_params[s].pad_bottom_y = scaler_luma->pad_right; 823 stripe_params[s].pad_bottom_uv = 824 scaler_chroma->pad_right; 825 stripe_params[s].crop_left_y = stripe_crop_left_y; 826 stripe_params[s].crop_top_y = scaler_luma->crop_top; 827 stripe_params[s].crop_left_uv = stripe_crop_left_uv; 828 stripe_params[s].crop_top_uv = scaler_chroma->crop_top; 829 stripe_params[s].start_column_y = stripe_offset_col_y; 830 stripe_params[s].start_column_uv = stripe_offset_col_uv; 831 stripe_params[s].chunk_width = reso.chunk_width; 832 stripe_params[s].chunk_height = reso.chunk_height; 833 stripe_params[s].block_width = reso.block_width; 834 stripe_params[s].block_height = reso.block_height; 835 } 836 } 837 838 return 0; 839} 840 841/* 842 * This function configures the Output Formatter System, given the number of 843 * stripes, scaler luma and chrome parameters 844 */ 845static int imgu_css_osys_calc(struct imgu_css *css, unsigned int pipe, 846 unsigned int stripes, 847 struct imgu_abi_osys_config *osys, 848 struct imgu_css_scaler_info *scaler_luma, 849 struct imgu_css_scaler_info *scaler_chroma, 850 struct imgu_abi_stripes block_stripes[]) 851{ 852 struct imgu_css_frame_params frame_params[IMGU_ABI_OSYS_PINS]; 853 struct imgu_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES]; 854 struct imgu_abi_osys_formatter_params *param; 855 unsigned int pin, s; 856 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 857 858 memset(osys, 0, sizeof(*osys)); 859 860 /* Compute the frame and stripe params */ 861 if (imgu_css_osys_calc_frame_and_stripe_params(css, stripes, osys, 862 scaler_luma, 863 scaler_chroma, 864 frame_params, 865 stripe_params, pipe)) 866 return -EINVAL; 867 868 /* Output formatter system parameters */ 869 870 for (s = 0; s < stripes; s++) { 871 struct imgu_abi_osys_scaler_params *scaler = 872 &osys->scaler[s].param; 873 int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT; 874 int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP; 875 876 /* OUTPUT 0 / PIN 0 is only Scaler output */ 877 scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR; 878 879 /* 880 * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC) 881 * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) / 882 * (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS) 883 * = 2 * 64 / 32 = 4 884 */ 885 scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE; 886 /* 887 * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size) 888 * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) + 889 * (VMEM1_y_size / 4) 890 * = (VMEM1_y_size) + (VMEM1_y_size / 4) + 891 * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4 892 * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE) 893 */ 894 scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE; 895 scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 896 IMGU_VMEM1_U_OFFSET; 897 scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 898 IMGU_VMEM1_V_OFFSET; 899 scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE; 900 scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE; 901 scaler->inp_buf_chunk_width = stripe_params[s].chunk_width; 902 scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS; 903 904 /* Output buffers */ 905 scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR; 906 scaler->out_buf_y_line_stride = stripe_params[s].block_width / 907 IMGU_VMEM1_ELEMS_PER_VEC; 908 scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE; 909 scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 910 IMGU_VMEM1_U_OFFSET; 911 scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 912 IMGU_VMEM1_V_OFFSET; 913 scaler->out_buf_uv_line_stride = stripe_params[s].block_width / 914 IMGU_VMEM1_ELEMS_PER_VEC / 2; 915 scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE; 916 scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS; 917 918 /* Intermediate buffers */ 919 scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR; 920 scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE; 921 scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR; 922 scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR; 923 scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE; 924 scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK; 925 scaler->int_buf_chunk_width = stripe_params[s].chunk_height; 926 scaler->int_buf_chunk_height = stripe_params[s].block_width; 927 928 /* Context buffers */ 929 scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR; 930 scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR; 931 scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR; 932 scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR; 933 scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR; 934 scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR; 935 936 /* Addresses for release-input and process-output tokens */ 937 scaler->release_inp_buf_addr = fifo_addr_ack; 938 scaler->release_inp_buf_en = 1; 939 scaler->release_out_buf_en = 1; 940 scaler->process_out_buf_addr = fifo_addr_fmt; 941 942 /* Settings dimensions, padding, cropping */ 943 scaler->input_image_y_width = stripe_params[s].input_width; 944 scaler->input_image_y_height = stripe_params[s].input_height; 945 scaler->input_image_y_start_column = 946 stripe_params[s].start_column_y; 947 scaler->input_image_uv_start_column = 948 stripe_params[s].start_column_uv; 949 scaler->input_image_y_left_pad = stripe_params[s].pad_left_y; 950 scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv; 951 scaler->input_image_y_right_pad = stripe_params[s].pad_right_y; 952 scaler->input_image_uv_right_pad = 953 stripe_params[s].pad_right_uv; 954 scaler->input_image_y_top_pad = stripe_params[s].pad_top_y; 955 scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv; 956 scaler->input_image_y_bottom_pad = 957 stripe_params[s].pad_bottom_y; 958 scaler->input_image_uv_bottom_pad = 959 stripe_params[s].pad_bottom_uv; 960 scaler->processing_mode = stripe_params[s].processing_mode; 961 scaler->scaling_ratio = stripe_params[s].phase_step; 962 scaler->y_left_phase_init = stripe_params[s].phase_init_left_y; 963 scaler->uv_left_phase_init = 964 stripe_params[s].phase_init_left_uv; 965 scaler->y_top_phase_init = stripe_params[s].phase_init_top_y; 966 scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv; 967 scaler->coeffs_exp_shift = stripe_params[s].exp_shift; 968 scaler->out_y_left_crop = stripe_params[s].crop_left_y; 969 scaler->out_uv_left_crop = stripe_params[s].crop_left_uv; 970 scaler->out_y_top_crop = stripe_params[s].crop_top_y; 971 scaler->out_uv_top_crop = stripe_params[s].crop_top_uv; 972 973 for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) { 974 int in_fifo_addr; 975 int out_fifo_addr; 976 int block_width_vecs; 977 int input_width_s; 978 int input_width_vecs; 979 int input_buf_y_st_addr; 980 int input_buf_u_st_addr; 981 int input_buf_v_st_addr; 982 int input_buf_y_line_stride; 983 int input_buf_uv_line_stride; 984 int output_buf_y_line_stride; 985 int output_buf_uv_line_stride; 986 int output_buf_nr_y_lines; 987 int block_height; 988 int block_width; 989 struct imgu_abi_osys_frame_params *fr_pr; 990 991 fr_pr = &osys->frame[pin].param; 992 993 /* Frame parameters */ 994 fr_pr->enable = frame_params[pin].enable; 995 fr_pr->format = frame_params[pin].format; 996 fr_pr->mirror = frame_params[pin].mirror; 997 fr_pr->flip = frame_params[pin].flip; 998 fr_pr->tiling = frame_params[pin].tiling; 999 fr_pr->width = frame_params[pin].width; 1000 fr_pr->height = frame_params[pin].height; 1001 fr_pr->stride = frame_params[pin].stride; 1002 fr_pr->scaled = frame_params[pin].scaled; 1003 1004 /* Stripe parameters */ 1005 osys->stripe[s].crop_top[pin] = 1006 frame_params[pin].crop_top; 1007 osys->stripe[s].input_width = 1008 stripe_params[s].input_width; 1009 osys->stripe[s].input_height = 1010 stripe_params[s].input_height; 1011 osys->stripe[s].block_height = 1012 stripe_params[s].block_height; 1013 osys->stripe[s].block_width = 1014 stripe_params[s].block_width; 1015 osys->stripe[s].output_width[pin] = 1016 stripe_params[s].output_width[pin]; 1017 osys->stripe[s].output_height[pin] = 1018 stripe_params[s].output_height[pin]; 1019 1020 if (s == 0) { 1021 /* Only first stripe should do left cropping */ 1022 osys->stripe[s].crop_left[pin] = 1023 frame_params[pin].crop_left; 1024 osys->stripe[s].output_offset[pin] = 1025 stripe_params[s].output_offset[pin]; 1026 } else { 1027 /* 1028 * Stripe offset for other strips should be 1029 * adjusted according to the cropping done 1030 * at the first strip 1031 */ 1032 osys->stripe[s].crop_left[pin] = 0; 1033 osys->stripe[s].output_offset[pin] = 1034 (stripe_params[s].output_offset[pin] - 1035 osys->stripe[0].crop_left[pin]); 1036 } 1037 1038 if (!frame_params[pin].enable) 1039 continue; 1040 1041 /* Formatter: configurations */ 1042 1043 /* 1044 * Get the dimensions of the input blocks of the 1045 * formatter, which is the same as the output 1046 * blocks of the scaler. 1047 */ 1048 if (frame_params[pin].scaled) { 1049 block_height = stripe_params[s].block_height; 1050 block_width = stripe_params[s].block_width; 1051 } else { 1052 block_height = IMGU_OSYS_BLOCK_HEIGHT; 1053 block_width = IMGU_OSYS_BLOCK_WIDTH; 1054 } 1055 block_width_vecs = 1056 block_width / IMGU_VMEM1_ELEMS_PER_VEC; 1057 /* 1058 * The input/output line stride depends on the 1059 * block size. 1060 */ 1061 input_buf_y_line_stride = block_width_vecs; 1062 input_buf_uv_line_stride = block_width_vecs / 2; 1063 output_buf_y_line_stride = block_width_vecs; 1064 output_buf_uv_line_stride = block_width_vecs / 2; 1065 output_buf_nr_y_lines = block_height; 1066 if (frame_params[pin].format == 1067 IMGU_ABI_OSYS_FORMAT_NV12 || 1068 frame_params[pin].format == 1069 IMGU_ABI_OSYS_FORMAT_NV21) 1070 output_buf_uv_line_stride = 1071 output_buf_y_line_stride; 1072 1073 /* 1074 * Tiled outputs use a different output buffer 1075 * configuration. The input (= scaler output) block 1076 * width translates to a tile height, and the block 1077 * height to the tile width. The default block size of 1078 * 128x32 maps exactly onto a 4kB tile (512x8) for Y. 1079 * For UV, the tile width is always half. 1080 */ 1081 if (frame_params[pin].tiling) { 1082 output_buf_nr_y_lines = 8; 1083 output_buf_y_line_stride = 512 / 1084 IMGU_VMEM1_ELEMS_PER_VEC; 1085 output_buf_uv_line_stride = 256 / 1086 IMGU_VMEM1_ELEMS_PER_VEC; 1087 } 1088 1089 /* 1090 * Store the output buffer line stride. Will be 1091 * used to compute buffer offsets in boundary 1092 * conditions when output blocks are partially 1093 * outside the image. 1094 */ 1095 osys->stripe[s].buf_stride[pin] = 1096 output_buf_y_line_stride * 1097 IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS; 1098 if (frame_params[pin].scaled) { 1099 /* 1100 * The input buffs are the intermediate 1101 * buffers (scalers' output) 1102 */ 1103 input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR; 1104 input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 1105 IMGU_VMEM1_U_OFFSET; 1106 input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 1107 IMGU_VMEM1_V_OFFSET; 1108 } else { 1109 /* 1110 * The input bufferss are the buffers 1111 * filled by the SP 1112 */ 1113 input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR; 1114 input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 1115 IMGU_VMEM1_U_OFFSET; 1116 input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 1117 IMGU_VMEM1_V_OFFSET; 1118 } 1119 1120 /* 1121 * The formatter input width must be rounded to 1122 * the block width. Otherwise the formatter will 1123 * not recognize the end of the line, resulting 1124 * in incorrect tiling (system may hang!) and 1125 * possibly other problems. 1126 */ 1127 input_width_s = 1128 roundup(stripe_params[s].output_width[pin], 1129 block_width); 1130 input_width_vecs = input_width_s / 1131 IMGU_VMEM1_ELEMS_PER_VEC; 1132 out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP; 1133 /* 1134 * Process-output tokens must be sent to the SP. 1135 * When scaling, the release-input tokens can be 1136 * sent directly to the scaler, otherwise the 1137 * formatter should send them to the SP. 1138 */ 1139 if (frame_params[pin].scaled) 1140 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER; 1141 else 1142 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP; 1143 1144 /* Formatter */ 1145 param = &osys->formatter[s][pin].param; 1146 1147 param->format = frame_params[pin].format; 1148 param->flip = frame_params[pin].flip; 1149 param->mirror = frame_params[pin].mirror; 1150 param->tiling = frame_params[pin].tiling; 1151 param->reduce_range = frame_params[pin].reduce_range; 1152 param->alpha_blending = 0; 1153 param->release_inp_addr = in_fifo_addr; 1154 param->release_inp_en = 1; 1155 param->process_out_buf_addr = out_fifo_addr; 1156 param->image_width_vecs = input_width_vecs; 1157 param->image_height_lines = 1158 stripe_params[s].output_height[pin]; 1159 param->inp_buff_y_st_addr = input_buf_y_st_addr; 1160 param->inp_buff_y_line_stride = input_buf_y_line_stride; 1161 param->inp_buff_y_buffer_stride = IMGU_VMEM1_BUF_SIZE; 1162 param->int_buff_u_st_addr = input_buf_u_st_addr; 1163 param->int_buff_v_st_addr = input_buf_v_st_addr; 1164 param->inp_buff_uv_line_stride = 1165 input_buf_uv_line_stride; 1166 param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE; 1167 param->out_buff_level = 0; 1168 param->out_buff_nr_y_lines = output_buf_nr_y_lines; 1169 param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET; 1170 param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET; 1171 param->out_buff_y_line_stride = 1172 output_buf_y_line_stride; 1173 param->out_buff_uv_line_stride = 1174 output_buf_uv_line_stride; 1175 param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR; 1176 param->hist_buff_line_stride = 1177 IMGU_VMEM1_HST_BUF_STRIDE; 1178 param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES; 1179 } 1180 } 1181 1182 block_stripes[0].offset = 0; 1183 if (stripes <= 1) { 1184 block_stripes[0].width = stripe_params[0].input_width; 1185 block_stripes[0].height = stripe_params[0].input_height; 1186 } else { 1187 struct imgu_fw_info *bi = 1188 &css->fwp->binary_header[css_pipe->bindex]; 1189 unsigned int sp_block_width = 1190 bi->info.isp.sp.block.block_width * 1191 IPU3_UAPI_ISP_VEC_ELEMS; 1192 1193 block_stripes[0].width = roundup(stripe_params[0].input_width, 1194 sp_block_width); 1195 block_stripes[1].offset = 1196 rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width - 1197 stripe_params[1].input_width, sp_block_width); 1198 block_stripes[1].width = 1199 roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width - 1200 block_stripes[1].offset, sp_block_width); 1201 block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height; 1202 block_stripes[1].height = block_stripes[0].height; 1203 } 1204 1205 return 0; 1206} 1207 1208/*********************** Mostly 3A operations ******************************/ 1209 1210/* 1211 * This function creates a "TO-DO list" (operations) for the sp code. 1212 * 1213 * There are 2 types of operations: 1214 * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to 1215 * accelerator space (NOTE that this space is limited) associated data: 1216 * DDR address + accelerator's config set index(acc's address). 1217 * 1218 * 2. Issue "Process Lines Command" to shd accelerator 1219 * associated data: #lines + which config set to use (actually, accelerator 1220 * will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction 1221 * of not touching config sets x & (x+1)%num_of_sets when process_lines(x) 1222 * is active). 1223 * 1224 * Basically there are 2 types of operations "chunks": 1225 * 1. "initial chunk": Initially, we do as much transfers as we can (and need) 1226 * [0 - max sets(3) ] followed by 1 or 2 "process lines" operations. 1227 * 1228 * 2. "regular chunk" - 1 transfer followed by 1 process line operation. 1229 * (in some cases we might need additional transfer ate the last chunk). 1230 * 1231 * for some case: 1232 * --> init 1233 * tr (0) 1234 * tr (1) 1235 * tr (2) 1236 * pl (0) 1237 * pl (1) 1238 * --> ack (0) 1239 * tr (3) 1240 * pl (2) 1241 * --> ack (1) 1242 * pl (3) 1243 * --> ack (2) 1244 * do nothing 1245 * --> ack (3) 1246 * do nothing 1247 */ 1248 1249static int 1250imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops, 1251 const struct ipu3_uapi_shd_grid_config *grid, 1252 unsigned int image_height) 1253{ 1254 unsigned int block_height = 1 << grid->block_height_log2; 1255 unsigned int grid_height_per_slice = grid->grid_height_per_slice; 1256 unsigned int set_height = grid_height_per_slice * block_height; 1257 1258 /* We currently support only abs(y_start) > grid_height_per_slice */ 1259 unsigned int positive_y_start = (unsigned int)-grid->y_start; 1260 unsigned int first_process_lines = 1261 set_height - (positive_y_start % set_height); 1262 unsigned int last_set_height; 1263 unsigned int num_of_sets; 1264 1265 struct imgu_abi_acc_operation *p_op; 1266 struct imgu_abi_acc_process_lines_cmd_data *p_pl; 1267 struct imgu_abi_shd_transfer_luts_set_data *p_tr; 1268 1269 unsigned int op_idx, pl_idx, tr_idx; 1270 unsigned char tr_set_num, pl_cfg_set; 1271 1272 /* 1273 * When the number of lines for the last process lines command 1274 * is equal to a set height, we need another line of grid cell - 1275 * additional transfer is required. 1276 */ 1277 unsigned char last_tr = 0; 1278 1279 /* Add "process lines" command to the list of operations */ 1280 bool add_pl; 1281 /* Add DMA xfer (config set) command to the list of ops */ 1282 bool add_tr; 1283 1284 /* 1285 * Available partial grid (the part that fits into #IMGU_SHD_SETS sets) 1286 * doesn't cover whole frame - need to process in chunks 1287 */ 1288 if (image_height > first_process_lines) { 1289 last_set_height = 1290 (image_height - first_process_lines) % set_height; 1291 num_of_sets = last_set_height > 0 ? 1292 (image_height - first_process_lines) / set_height + 2 : 1293 (image_height - first_process_lines) / set_height + 1; 1294 last_tr = (set_height - last_set_height <= block_height || 1295 last_set_height == 0) ? 1 : 0; 1296 } else { /* partial grid covers whole frame */ 1297 last_set_height = 0; 1298 num_of_sets = 1; 1299 first_process_lines = image_height; 1300 last_tr = set_height - image_height <= block_height ? 1 : 0; 1301 } 1302 1303 /* Init operations lists and counters */ 1304 p_op = ops->operation_list; 1305 op_idx = 0; 1306 p_pl = ops->process_lines_data; 1307 pl_idx = 0; 1308 p_tr = ops->transfer_data; 1309 tr_idx = 0; 1310 1311 memset(ops, 0, sizeof(*ops)); 1312 1313 /* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */ 1314 tr_set_num = 0; 1315 pl_cfg_set = 0; 1316 1317 /* 1318 * Always start with a transfer - process lines command must be 1319 * initiated only after appropriate config sets are in place 1320 * (2 configuration sets per process line command, except for last one). 1321 */ 1322 add_pl = false; 1323 add_tr = true; 1324 1325 while (add_pl || add_tr) { 1326 /* Transfer ops */ 1327 if (add_tr) { 1328 if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS || 1329 tr_idx >= IMGU_ABI_SHD_MAX_TRANSFERS) 1330 return -EINVAL; 1331 p_op[op_idx].op_type = 1332 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA; 1333 p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE; 1334 op_idx++; 1335 p_tr[tr_idx].set_number = tr_set_num; 1336 tr_idx++; 1337 tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS; 1338 } 1339 1340 /* Process-lines ops */ 1341 if (add_pl) { 1342 if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS || 1343 pl_idx >= IMGU_ABI_SHD_MAX_PROCESS_LINES) 1344 return -EINVAL; 1345 p_op[op_idx].op_type = 1346 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES; 1347 1348 /* 1349 * In case we have 2 process lines commands - 1350 * don't stop after the first one 1351 */ 1352 if (pl_idx == 0 && num_of_sets != 1) 1353 p_op[op_idx].op_indicator = 1354 IMGU_ABI_ACC_OP_IDLE; 1355 /* 1356 * Initiate last process lines command - 1357 * end of operation list. 1358 */ 1359 else if (pl_idx == num_of_sets - 1) 1360 p_op[op_idx].op_indicator = 1361 IMGU_ABI_ACC_OP_END_OF_OPS; 1362 /* 1363 * Intermediate process line command - end of operation 1364 * "chunk" (meaning few "transfers" followed by few 1365 * "process lines" commands). 1366 */ 1367 else 1368 p_op[op_idx].op_indicator = 1369 IMGU_ABI_ACC_OP_END_OF_ACK; 1370 1371 op_idx++; 1372 1373 /* first process line operation */ 1374 if (pl_idx == 0) 1375 p_pl[pl_idx].lines = first_process_lines; 1376 /* Last process line operation */ 1377 else if (pl_idx == num_of_sets - 1 && 1378 last_set_height > 0) 1379 p_pl[pl_idx].lines = last_set_height; 1380 else /* "regular" process lines operation */ 1381 p_pl[pl_idx].lines = set_height; 1382 1383 p_pl[pl_idx].cfg_set = pl_cfg_set; 1384 pl_idx++; 1385 pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS; 1386 } 1387 1388 /* 1389 * Initially, we always transfer 1390 * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the 1391 * corresponding process lines commands. 1392 */ 1393 if (tr_idx == IMGU_SHD_SETS || 1394 tr_idx == num_of_sets + last_tr) { 1395 add_tr = false; 1396 add_pl = true; 1397 } 1398 1399 /* 1400 * We have finished the "initial" operations chunk - 1401 * be ready to get more chunks. 1402 */ 1403 if (pl_idx == 2) { 1404 add_tr = true; 1405 add_pl = true; 1406 } 1407 1408 /* Stop conditions for each operation type */ 1409 if (tr_idx == num_of_sets + last_tr) 1410 add_tr = false; 1411 if (pl_idx == num_of_sets) 1412 add_pl = false; 1413 } 1414 1415 return 0; 1416} 1417 1418/* 1419 * The follow handshake procotol is the same for AF, AWB and AWB FR. 1420 * 1421 * for n sets of meta-data, the flow is: 1422 * --> init 1423 * process-lines (0) 1424 * process-lines (1) eoc 1425 * --> ack (0) 1426 * read-meta-data (0) 1427 * process-lines (2) eoc 1428 * --> ack (1) 1429 * read-meta-data (1) 1430 * process-lines (3) eoc 1431 * ... 1432 * 1433 * --> ack (n-3) 1434 * read-meta-data (n-3) 1435 * process-lines (n-1) eoc 1436 * --> ack (n-2) 1437 * read-meta-data (n-2) eoc 1438 * --> ack (n-1) 1439 * read-meta-data (n-1) eof 1440 * 1441 * for 2 sets we get: 1442 * --> init 1443 * pl (0) 1444 * pl (1) eoc 1445 * --> ack (0) 1446 * pl (2) - rest of image, if applicable) 1447 * rmd (0) eoc 1448 * --> ack (1) 1449 * rmd (1) eof 1450 * --> (ack (2)) 1451 * do nothing 1452 * 1453 * for only one set: 1454 * 1455 * --> init 1456 * pl(0) eoc 1457 * --> ack (0) 1458 * rmd (0) eof 1459 * 1460 * grid smaller than image case 1461 * for example 128x128 grid (block size 8x8, 16x16 num of blocks) 1462 * start at (0,0) 1463 * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal 1464 * => 1st process lines = 80 1465 * we're left with 128-80=48 lines (6 blocks vertical) 1466 * => 2nd process lines = 48 1467 * last process lines to cover the image - image_height - 128 1468 * 1469 * --> init 1470 * pl (0) first 1471 * pl (1) last-in-grid 1472 * --> ack (0) 1473 * rmd (0) 1474 * pl (2) after-grid 1475 * --> ack (1) 1476 * rmd (1) eof 1477 * --> ack (2) 1478 * do nothing 1479 */ 1480struct process_lines { 1481 unsigned int image_height; 1482 unsigned short grid_height; 1483 unsigned short block_height; 1484 unsigned short y_start; 1485 unsigned char grid_height_per_slice; 1486 1487 unsigned short max_op; /* max operation */ 1488 unsigned short max_tr; /* max transaction */ 1489 unsigned char acc_enable; 1490}; 1491 1492/* Helper to config intra_frame_operations_data. */ 1493static int 1494imgu_css_acc_process_lines(const struct process_lines *pl, 1495 struct imgu_abi_acc_operation *p_op, 1496 struct imgu_abi_acc_process_lines_cmd_data *p_pl, 1497 struct imgu_abi_acc_transfer_op_data *p_tr) 1498{ 1499 unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0; 1500 unsigned char tr_set_num = 0, pl_cfg_set = 0; 1501 const unsigned short grid_last_line = 1502 pl->y_start + pl->grid_height * pl->block_height; 1503 const unsigned short process_lines = 1504 pl->grid_height_per_slice * pl->block_height; 1505 1506 unsigned int process_lines_after_grid; 1507 unsigned short first_process_lines; 1508 unsigned short last_process_lines_in_grid; 1509 1510 unsigned short num_of_process_lines; 1511 unsigned short num_of_sets; 1512 1513 if (pl->grid_height_per_slice == 0) 1514 return -EINVAL; 1515 1516 if (pl->acc_enable && grid_last_line > pl->image_height) 1517 return -EINVAL; 1518 1519 num_of_sets = pl->grid_height / pl->grid_height_per_slice; 1520 if (num_of_sets * pl->grid_height_per_slice < pl->grid_height) 1521 num_of_sets++; 1522 1523 /* Account for two line delay inside the FF */ 1524 if (pl->max_op == IMGU_ABI_AF_MAX_OPERATIONS) { 1525 first_process_lines = process_lines + pl->y_start + 2; 1526 last_process_lines_in_grid = 1527 (grid_last_line - first_process_lines) - 1528 ((num_of_sets - 2) * process_lines) + 4; 1529 process_lines_after_grid = 1530 pl->image_height - grid_last_line - 4; 1531 } else { 1532 first_process_lines = process_lines + pl->y_start; 1533 last_process_lines_in_grid = 1534 (grid_last_line - first_process_lines) - 1535 ((num_of_sets - 2) * process_lines); 1536 process_lines_after_grid = pl->image_height - grid_last_line; 1537 } 1538 1539 num_of_process_lines = num_of_sets; 1540 if (process_lines_after_grid > 0) 1541 num_of_process_lines++; 1542 1543 while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) { 1544 /* Read meta-data */ 1545 if (pl_idx >= 2 || (pl_idx == 1 && num_of_sets == 1)) { 1546 if (op_idx >= pl->max_op || tr_idx >= pl->max_tr) 1547 return -EINVAL; 1548 1549 p_op[op_idx].op_type = 1550 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA; 1551 1552 if (tr_idx == num_of_sets - 1) 1553 /* The last operation is always a tr */ 1554 p_op[op_idx].op_indicator = 1555 IMGU_ABI_ACC_OP_END_OF_OPS; 1556 else if (tr_idx == num_of_sets - 2) 1557 if (process_lines_after_grid == 0) 1558 /* 1559 * No additional pl op left - 1560 * this op is left as lats of cycle 1561 */ 1562 p_op[op_idx].op_indicator = 1563 IMGU_ABI_ACC_OP_END_OF_ACK; 1564 else 1565 /* 1566 * We still have to process-lines after 1567 * the grid so have one more pl op 1568 */ 1569 p_op[op_idx].op_indicator = 1570 IMGU_ABI_ACC_OP_IDLE; 1571 else 1572 /* Default - usually there's a pl after a tr */ 1573 p_op[op_idx].op_indicator = 1574 IMGU_ABI_ACC_OP_IDLE; 1575 1576 op_idx++; 1577 if (p_tr) { 1578 p_tr[tr_idx].set_number = tr_set_num; 1579 tr_set_num = 1 - tr_set_num; 1580 } 1581 tr_idx++; 1582 } 1583 1584 /* process_lines */ 1585 if (pl_idx < num_of_process_lines) { 1586 if (op_idx >= pl->max_op || pl_idx >= pl->max_tr) 1587 return -EINVAL; 1588 1589 p_op[op_idx].op_type = 1590 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES; 1591 if (pl_idx == 0) 1592 if (num_of_process_lines == 1) 1593 /* Only one pl op */ 1594 p_op[op_idx].op_indicator = 1595 IMGU_ABI_ACC_OP_END_OF_ACK; 1596 else 1597 /* On init - do two pl ops */ 1598 p_op[op_idx].op_indicator = 1599 IMGU_ABI_ACC_OP_IDLE; 1600 else 1601 /* Usually pl is the end of the ack cycle */ 1602 p_op[op_idx].op_indicator = 1603 IMGU_ABI_ACC_OP_END_OF_ACK; 1604 1605 op_idx++; 1606 1607 if (pl_idx == 0) 1608 /* First process line */ 1609 p_pl[pl_idx].lines = first_process_lines; 1610 else if (pl_idx == num_of_sets - 1) 1611 /* Last in grid */ 1612 p_pl[pl_idx].lines = last_process_lines_in_grid; 1613 else if (pl_idx == num_of_process_lines - 1) 1614 /* After the grid */ 1615 p_pl[pl_idx].lines = process_lines_after_grid; 1616 else 1617 /* Inside the grid */ 1618 p_pl[pl_idx].lines = process_lines; 1619 1620 if (p_tr) { 1621 p_pl[pl_idx].cfg_set = pl_cfg_set; 1622 pl_cfg_set = 1 - pl_cfg_set; 1623 } 1624 pl_idx++; 1625 } 1626 } 1627 1628 return 0; 1629} 1630 1631static int imgu_css_af_ops_calc(struct imgu_css *css, unsigned int pipe, 1632 struct imgu_abi_af_config *af_config) 1633{ 1634 struct imgu_abi_af_intra_frame_operations_data *to = 1635 &af_config->operations_data; 1636 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1637 struct imgu_fw_info *bi = 1638 &css->fwp->binary_header[css_pipe->bindex]; 1639 1640 struct process_lines pl = { 1641 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height, 1642 .grid_height = af_config->config.grid_cfg.height, 1643 .block_height = 1644 1 << af_config->config.grid_cfg.block_height_log2, 1645 .y_start = af_config->config.grid_cfg.y_start & 1646 IPU3_UAPI_GRID_START_MASK, 1647 .grid_height_per_slice = 1648 af_config->stripes[0].grid_cfg.height_per_slice, 1649 .max_op = IMGU_ABI_AF_MAX_OPERATIONS, 1650 .max_tr = IMGU_ABI_AF_MAX_TRANSFERS, 1651 .acc_enable = bi->info.isp.sp.enable.af, 1652 }; 1653 1654 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data, 1655 NULL); 1656} 1657 1658static int 1659imgu_css_awb_fr_ops_calc(struct imgu_css *css, unsigned int pipe, 1660 struct imgu_abi_awb_fr_config *awb_fr_config) 1661{ 1662 struct imgu_abi_awb_fr_intra_frame_operations_data *to = 1663 &awb_fr_config->operations_data; 1664 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1665 struct imgu_fw_info *bi = 1666 &css->fwp->binary_header[css_pipe->bindex]; 1667 struct process_lines pl = { 1668 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height, 1669 .grid_height = awb_fr_config->config.grid_cfg.height, 1670 .block_height = 1671 1 << awb_fr_config->config.grid_cfg.block_height_log2, 1672 .y_start = awb_fr_config->config.grid_cfg.y_start & 1673 IPU3_UAPI_GRID_START_MASK, 1674 .grid_height_per_slice = 1675 awb_fr_config->stripes[0].grid_cfg.height_per_slice, 1676 .max_op = IMGU_ABI_AWB_FR_MAX_OPERATIONS, 1677 .max_tr = IMGU_ABI_AWB_FR_MAX_PROCESS_LINES, 1678 .acc_enable = bi->info.isp.sp.enable.awb_fr_acc, 1679 }; 1680 1681 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data, 1682 NULL); 1683} 1684 1685static int imgu_css_awb_ops_calc(struct imgu_css *css, unsigned int pipe, 1686 struct imgu_abi_awb_config *awb_config) 1687{ 1688 struct imgu_abi_awb_intra_frame_operations_data *to = 1689 &awb_config->operations_data; 1690 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1691 struct imgu_fw_info *bi = 1692 &css->fwp->binary_header[css_pipe->bindex]; 1693 1694 struct process_lines pl = { 1695 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height, 1696 .grid_height = awb_config->config.grid.height, 1697 .block_height = 1698 1 << awb_config->config.grid.block_height_log2, 1699 .y_start = awb_config->config.grid.y_start, 1700 .grid_height_per_slice = 1701 awb_config->stripes[0].grid.height_per_slice, 1702 .max_op = IMGU_ABI_AWB_MAX_OPERATIONS, 1703 .max_tr = IMGU_ABI_AWB_MAX_TRANSFERS, 1704 .acc_enable = bi->info.isp.sp.enable.awb_acc, 1705 }; 1706 1707 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data, 1708 to->transfer_data); 1709} 1710 1711static u16 imgu_css_grid_end(u16 start, u8 width, u8 block_width_log2) 1712{ 1713 return (start & IPU3_UAPI_GRID_START_MASK) + 1714 (width << block_width_log2) - 1; 1715} 1716 1717static void imgu_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg) 1718{ 1719 grid_cfg->x_end = imgu_css_grid_end(grid_cfg->x_start, grid_cfg->width, 1720 grid_cfg->block_width_log2); 1721 grid_cfg->y_end = imgu_css_grid_end(grid_cfg->y_start, grid_cfg->height, 1722 grid_cfg->block_height_log2); 1723} 1724 1725/****************** config computation *****************************/ 1726 1727static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe, 1728 struct imgu_abi_acc_param *acc) 1729{ 1730 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1731 const struct imgu_fw_info *bi = 1732 &css->fwp->binary_header[css_pipe->bindex]; 1733 struct imgu_css_scaler_info scaler_luma, scaler_chroma; 1734 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes; 1735 const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2; 1736 unsigned int bds_ds, i; 1737 1738 memset(acc, 0, sizeof(*acc)); 1739 1740 /* acc_param: osys_config */ 1741 1742 if (imgu_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma, 1743 &scaler_chroma, acc->stripe.block_stripes)) 1744 return -EINVAL; 1745 1746 /* acc_param: stripe data */ 1747 1748 /* 1749 * For the striped case the approach is as follows: 1750 * 1. down-scaled stripes are calculated - with 128 overlap 1751 * (this is the main limiter therefore it's first) 1752 * 2. input stripes are derived by up-scaling the down-scaled stripes 1753 * (there are no alignment requirements on input stripes) 1754 * 3. output stripes are derived from down-scaled stripes too 1755 */ 1756 1757 acc->stripe.num_of_stripes = stripes; 1758 acc->stripe.input_frame.width = 1759 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width; 1760 acc->stripe.input_frame.height = 1761 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height; 1762 acc->stripe.input_frame.bayer_order = 1763 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order; 1764 1765 for (i = 0; i < stripes; i++) 1766 acc->stripe.bds_out_stripes[i].height = 1767 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1768 acc->stripe.bds_out_stripes[0].offset = 0; 1769 if (stripes <= 1) { 1770 acc->stripe.bds_out_stripes[0].width = 1771 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f); 1772 } else { 1773 /* Image processing is divided into two stripes */ 1774 acc->stripe.bds_out_stripes[0].width = 1775 acc->stripe.bds_out_stripes[1].width = 1776 (css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f; 1777 /* 1778 * Sum of width of the two stripes should not be smaller 1779 * than output width and must be even times of overlapping 1780 * unit f. 1781 */ 1782 if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) != 1783 !!(css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) 1784 acc->stripe.bds_out_stripes[0].width += f; 1785 if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) && 1786 (css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) { 1787 acc->stripe.bds_out_stripes[0].width += f; 1788 acc->stripe.bds_out_stripes[1].width += f; 1789 } 1790 /* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */ 1791 acc->stripe.bds_out_stripes[1].offset = 1792 acc->stripe.bds_out_stripes[0].width - 2 * f; 1793 } 1794 1795 acc->stripe.effective_stripes[0].height = 1796 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height; 1797 acc->stripe.effective_stripes[0].offset = 0; 1798 acc->stripe.bds_out_stripes_no_overlap[0].height = 1799 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1800 acc->stripe.bds_out_stripes_no_overlap[0].offset = 0; 1801 acc->stripe.output_stripes[0].height = 1802 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 1803 acc->stripe.output_stripes[0].offset = 0; 1804 if (stripes <= 1) { 1805 acc->stripe.down_scaled_stripes[0].width = 1806 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 1807 acc->stripe.down_scaled_stripes[0].height = 1808 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1809 acc->stripe.down_scaled_stripes[0].offset = 0; 1810 1811 acc->stripe.effective_stripes[0].width = 1812 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width; 1813 acc->stripe.bds_out_stripes_no_overlap[0].width = 1814 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f); 1815 1816 acc->stripe.output_stripes[0].width = 1817 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width; 1818 } else { /* Two stripes */ 1819 bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width * 1820 IMGU_BDS_GRANULARITY / 1821 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 1822 1823 acc->stripe.down_scaled_stripes[0] = 1824 acc->stripe.bds_out_stripes[0]; 1825 acc->stripe.down_scaled_stripes[1] = 1826 acc->stripe.bds_out_stripes[1]; 1827 if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)) 1828 acc->stripe.down_scaled_stripes[1].width += 1829 (css_pipe->rect[IPU3_CSS_RECT_BDS].width 1830 & (f - 1)) - f; 1831 1832 acc->stripe.effective_stripes[0].width = bds_ds * 1833 acc->stripe.down_scaled_stripes[0].width / 1834 IMGU_BDS_GRANULARITY; 1835 acc->stripe.effective_stripes[1].width = bds_ds * 1836 acc->stripe.down_scaled_stripes[1].width / 1837 IMGU_BDS_GRANULARITY; 1838 acc->stripe.effective_stripes[1].height = 1839 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height; 1840 acc->stripe.effective_stripes[1].offset = bds_ds * 1841 acc->stripe.down_scaled_stripes[1].offset / 1842 IMGU_BDS_GRANULARITY; 1843 1844 acc->stripe.bds_out_stripes_no_overlap[0].width = 1845 acc->stripe.bds_out_stripes_no_overlap[1].offset = 1846 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2; 1847 acc->stripe.bds_out_stripes_no_overlap[1].width = 1848 DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f) 1849 / 2 * f; 1850 acc->stripe.bds_out_stripes_no_overlap[1].height = 1851 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1852 1853 acc->stripe.output_stripes[0].width = 1854 acc->stripe.down_scaled_stripes[0].width - f; 1855 acc->stripe.output_stripes[1].width = 1856 acc->stripe.down_scaled_stripes[1].width - f; 1857 acc->stripe.output_stripes[1].height = 1858 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 1859 acc->stripe.output_stripes[1].offset = 1860 acc->stripe.output_stripes[0].width; 1861 } 1862 1863 acc->stripe.output_system_in_frame_width = 1864 css_pipe->rect[IPU3_CSS_RECT_GDC].width; 1865 acc->stripe.output_system_in_frame_height = 1866 css_pipe->rect[IPU3_CSS_RECT_GDC].height; 1867 1868 acc->stripe.effective_frame_width = 1869 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width; 1870 acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width; 1871 acc->stripe.out_frame_width = 1872 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width; 1873 acc->stripe.out_frame_height = 1874 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 1875 acc->stripe.gdc_in_buffer_width = 1876 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline / 1877 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel; 1878 acc->stripe.gdc_in_buffer_height = 1879 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height; 1880 acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X; 1881 acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y; 1882 acc->stripe.display_frame_width = 1883 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width; 1884 acc->stripe.display_frame_height = 1885 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height; 1886 acc->stripe.bds_aligned_frame_width = 1887 roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 1888 2 * IPU3_UAPI_ISP_VEC_ELEMS); 1889 1890 if (stripes > 1) 1891 acc->stripe.half_overlap_vectors = 1892 IMGU_STRIPE_FIXED_HALF_OVERLAP; 1893 else 1894 acc->stripe.half_overlap_vectors = 0; 1895 1896 return 0; 1897} 1898 1899static void imgu_css_cfg_acc_dvs(struct imgu_css *css, 1900 struct imgu_abi_acc_param *acc, 1901 unsigned int pipe) 1902{ 1903 unsigned int i; 1904 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1905 1906 /* Disable DVS statistics */ 1907 acc->dvs_stat.operations_data.process_lines_data[0].lines = 1908 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1909 acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0; 1910 acc->dvs_stat.operations_data.ops[0].op_type = 1911 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES; 1912 acc->dvs_stat.operations_data.ops[0].op_indicator = 1913 IMGU_ABI_ACC_OP_NO_OPS; 1914 for (i = 0; i < IMGU_ABI_DVS_STAT_LEVELS; i++) 1915 acc->dvs_stat.cfg.grd_config[i].enable = 0; 1916} 1917 1918static void acc_bds_per_stripe_data(struct imgu_css *css, 1919 struct imgu_abi_acc_param *acc, 1920 const int i, unsigned int pipe) 1921{ 1922 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1923 1924 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0; 1925 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0; 1926 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0; 1927 acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 = 1928 acc->bds.hor.hor_ctrl0; 1929 acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width = 1930 acc->stripe.down_scaled_stripes[i].width; 1931 acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width = 1932 acc->stripe.down_scaled_stripes[i].width; 1933 acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height = 1934 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1935} 1936 1937/* 1938 * Configure `acc' parameters. `acc_old' contains the old values (or is NULL) 1939 * and `acc_user' contains new prospective values. `use' contains flags 1940 * telling which fields to take from the old values (or generate if it is NULL) 1941 * and which to take from the new user values. 1942 */ 1943int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, 1944 struct ipu3_uapi_flags *use, 1945 struct imgu_abi_acc_param *acc, 1946 struct imgu_abi_acc_param *acc_old, 1947 struct ipu3_uapi_acc_param *acc_user) 1948{ 1949 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1950 const struct imgu_fw_info *bi = 1951 &css->fwp->binary_header[css_pipe->bindex]; 1952 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes; 1953 const unsigned int tnr_frame_width = 1954 acc->stripe.bds_aligned_frame_width; 1955 const unsigned int min_overlap = 10; 1956 const struct v4l2_pix_format_mplane *pixm = 1957 &css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix; 1958 const struct imgu_css_bds_config *cfg_bds; 1959 struct imgu_abi_input_feeder_data *feeder_data; 1960 1961 unsigned int bds_ds, ofs_x, ofs_y, i, width, height; 1962 u8 b_w_log2; /* Block width log2 */ 1963 1964 /* Update stripe using chroma and luma */ 1965 1966 if (imgu_css_cfg_acc_stripe(css, pipe, acc)) 1967 return -EINVAL; 1968 1969 /* acc_param: input_feeder_config */ 1970 1971 ofs_x = ((pixm->width - 1972 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1; 1973 ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1974 IMGU_ABI_BAYER_ORDER_RGGB || 1975 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1976 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0; 1977 ofs_y = ((pixm->height - 1978 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1; 1979 ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1980 IMGU_ABI_BAYER_ORDER_BGGR || 1981 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1982 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0; 1983 acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline; 1984 acc->input_feeder.data.start_row_address = 1985 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD + 1986 ofs_y * acc->input_feeder.data.row_stride; 1987 acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD; 1988 1989 acc->input_feeder.data_per_stripe.input_feeder_data[0].data = 1990 acc->input_feeder.data; 1991 1992 ofs_x += acc->stripe.effective_stripes[1].offset; 1993 1994 feeder_data = 1995 &acc->input_feeder.data_per_stripe.input_feeder_data[1].data; 1996 feeder_data->row_stride = acc->input_feeder.data.row_stride; 1997 feeder_data->start_row_address = 1998 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD + 1999 ofs_y * acc->input_feeder.data.row_stride; 2000 feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD; 2001 2002 /* acc_param: bnr_static_config */ 2003 2004 /* 2005 * Originate from user or be the original default values if user has 2006 * never set them before, when user gives a new set of parameters, 2007 * for each chunk in the parameter structure there is a flag use->xxx 2008 * whether to use the user-provided parameter or not. If not, the 2009 * parameter remains unchanged in the driver: 2010 * it's value is taken from acc_old. 2011 */ 2012 if (use && use->acc_bnr) { 2013 /* Take values from user */ 2014 acc->bnr = acc_user->bnr; 2015 } else if (acc_old) { 2016 /* Use old value */ 2017 acc->bnr = acc_old->bnr; 2018 } else { 2019 /* Calculate from scratch */ 2020 acc->bnr = imgu_css_bnr_defaults; 2021 } 2022 2023 acc->bnr.column_size = tnr_frame_width; 2024 2025 /* acc_param: bnr_static_config_green_disparity */ 2026 2027 if (use && use->acc_green_disparity) { 2028 /* Take values from user */ 2029 acc->green_disparity = acc_user->green_disparity; 2030 } else if (acc_old) { 2031 /* Use old value */ 2032 acc->green_disparity = acc_old->green_disparity; 2033 } else { 2034 /* Calculate from scratch */ 2035 memset(&acc->green_disparity, 0, sizeof(acc->green_disparity)); 2036 } 2037 2038 /* acc_param: dm_config */ 2039 2040 if (use && use->acc_dm) { 2041 /* Take values from user */ 2042 acc->dm = acc_user->dm; 2043 } else if (acc_old) { 2044 /* Use old value */ 2045 acc->dm = acc_old->dm; 2046 } else { 2047 /* Calculate from scratch */ 2048 acc->dm = imgu_css_dm_defaults; 2049 } 2050 2051 acc->dm.frame_width = tnr_frame_width; 2052 2053 /* acc_param: ccm_mat_config */ 2054 2055 if (use && use->acc_ccm) { 2056 /* Take values from user */ 2057 acc->ccm = acc_user->ccm; 2058 } else if (acc_old) { 2059 /* Use old value */ 2060 acc->ccm = acc_old->ccm; 2061 } else { 2062 /* Calculate from scratch */ 2063 acc->ccm = imgu_css_ccm_defaults; 2064 } 2065 2066 /* acc_param: gamma_config */ 2067 2068 if (use && use->acc_gamma) { 2069 /* Take values from user */ 2070 acc->gamma = acc_user->gamma; 2071 } else if (acc_old) { 2072 /* Use old value */ 2073 acc->gamma = acc_old->gamma; 2074 } else { 2075 /* Calculate from scratch */ 2076 acc->gamma.gc_ctrl.enable = 1; 2077 acc->gamma.gc_lut = imgu_css_gamma_lut; 2078 } 2079 2080 /* acc_param: csc_mat_config */ 2081 2082 if (use && use->acc_csc) { 2083 /* Take values from user */ 2084 acc->csc = acc_user->csc; 2085 } else if (acc_old) { 2086 /* Use old value */ 2087 acc->csc = acc_old->csc; 2088 } else { 2089 /* Calculate from scratch */ 2090 acc->csc = imgu_css_csc_defaults; 2091 } 2092 2093 /* acc_param: cds_params */ 2094 2095 if (use && use->acc_cds) { 2096 /* Take values from user */ 2097 acc->cds = acc_user->cds; 2098 } else if (acc_old) { 2099 /* Use old value */ 2100 acc->cds = acc_old->cds; 2101 } else { 2102 /* Calculate from scratch */ 2103 acc->cds = imgu_css_cds_defaults; 2104 } 2105 2106 /* acc_param: shd_config */ 2107 2108 if (use && use->acc_shd) { 2109 /* Take values from user */ 2110 acc->shd.shd = acc_user->shd.shd; 2111 acc->shd.shd_lut = acc_user->shd.shd_lut; 2112 } else if (acc_old) { 2113 /* Use old value */ 2114 acc->shd.shd = acc_old->shd.shd; 2115 acc->shd.shd_lut = acc_old->shd.shd_lut; 2116 } else { 2117 /* Calculate from scratch */ 2118 acc->shd.shd = imgu_css_shd_defaults; 2119 memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut)); 2120 } 2121 2122 if (acc->shd.shd.grid.width <= 0) 2123 return -EINVAL; 2124 2125 acc->shd.shd.grid.grid_height_per_slice = 2126 IMGU_ABI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width; 2127 2128 if (acc->shd.shd.grid.grid_height_per_slice <= 0) 2129 return -EINVAL; 2130 2131 acc->shd.shd.general.init_set_vrt_offst_ul = 2132 (-acc->shd.shd.grid.y_start >> 2133 acc->shd.shd.grid.block_height_log2) % 2134 acc->shd.shd.grid.grid_height_per_slice; 2135 2136 if (imgu_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid, 2137 css_pipe->rect[IPU3_CSS_RECT_BDS].height)) 2138 return -EINVAL; 2139 2140 /* acc_param: dvs_stat_config */ 2141 imgu_css_cfg_acc_dvs(css, acc, pipe); 2142 2143 /* acc_param: yuvp1_iefd_config */ 2144 2145 if (use && use->acc_iefd) { 2146 /* Take values from user */ 2147 acc->iefd = acc_user->iefd; 2148 } else if (acc_old) { 2149 /* Use old value */ 2150 acc->iefd = acc_old->iefd; 2151 } else { 2152 /* Calculate from scratch */ 2153 acc->iefd = imgu_css_iefd_defaults; 2154 } 2155 2156 /* acc_param: yuvp1_yds_config yds_c0 */ 2157 2158 if (use && use->acc_yds_c0) { 2159 /* Take values from user */ 2160 acc->yds_c0 = acc_user->yds_c0; 2161 } else if (acc_old) { 2162 /* Use old value */ 2163 acc->yds_c0 = acc_old->yds_c0; 2164 } else { 2165 /* Calculate from scratch */ 2166 acc->yds_c0 = imgu_css_yds_defaults; 2167 } 2168 2169 /* acc_param: yuvp1_chnr_config chnr_c0 */ 2170 2171 if (use && use->acc_chnr_c0) { 2172 /* Take values from user */ 2173 acc->chnr_c0 = acc_user->chnr_c0; 2174 } else if (acc_old) { 2175 /* Use old value */ 2176 acc->chnr_c0 = acc_old->chnr_c0; 2177 } else { 2178 /* Calculate from scratch */ 2179 acc->chnr_c0 = imgu_css_chnr_defaults; 2180 } 2181 2182 /* acc_param: yuvp1_y_ee_nr_config */ 2183 2184 if (use && use->acc_y_ee_nr) { 2185 /* Take values from user */ 2186 acc->y_ee_nr = acc_user->y_ee_nr; 2187 } else if (acc_old) { 2188 /* Use old value */ 2189 acc->y_ee_nr = acc_old->y_ee_nr; 2190 } else { 2191 /* Calculate from scratch */ 2192 acc->y_ee_nr = imgu_css_y_ee_nr_defaults; 2193 } 2194 2195 /* acc_param: yuvp1_yds_config yds */ 2196 2197 if (use && use->acc_yds) { 2198 /* Take values from user */ 2199 acc->yds = acc_user->yds; 2200 } else if (acc_old) { 2201 /* Use old value */ 2202 acc->yds = acc_old->yds; 2203 } else { 2204 /* Calculate from scratch */ 2205 acc->yds = imgu_css_yds_defaults; 2206 } 2207 2208 /* acc_param: yuvp1_chnr_config chnr */ 2209 2210 if (use && use->acc_chnr) { 2211 /* Take values from user */ 2212 acc->chnr = acc_user->chnr; 2213 } else if (acc_old) { 2214 /* Use old value */ 2215 acc->chnr = acc_old->chnr; 2216 } else { 2217 /* Calculate from scratch */ 2218 acc->chnr = imgu_css_chnr_defaults; 2219 } 2220 2221 /* acc_param: yuvp2_y_tm_lut_static_config */ 2222 2223 for (i = 0; i < IMGU_ABI_YUVP2_YTM_LUT_ENTRIES; i++) 2224 acc->ytm.entries[i] = i * 32; 2225 acc->ytm.enable = 0; /* Always disabled on IPU3 */ 2226 2227 /* acc_param: yuvp1_yds_config yds2 */ 2228 2229 if (use && use->acc_yds2) { 2230 /* Take values from user */ 2231 acc->yds2 = acc_user->yds2; 2232 } else if (acc_old) { 2233 /* Use old value */ 2234 acc->yds2 = acc_old->yds2; 2235 } else { 2236 /* Calculate from scratch */ 2237 acc->yds2 = imgu_css_yds_defaults; 2238 } 2239 2240 /* acc_param: yuvp2_tcc_static_config */ 2241 2242 if (use && use->acc_tcc) { 2243 /* Take values from user */ 2244 acc->tcc = acc_user->tcc; 2245 } else if (acc_old) { 2246 /* Use old value */ 2247 acc->tcc = acc_old->tcc; 2248 } else { 2249 /* Calculate from scratch */ 2250 memset(&acc->tcc, 0, sizeof(acc->tcc)); 2251 2252 acc->tcc.gen_control.en = 1; 2253 acc->tcc.gen_control.blend_shift = 3; 2254 acc->tcc.gen_control.gain_according_to_y_only = 1; 2255 acc->tcc.gen_control.gamma = 8; 2256 acc->tcc.gen_control.delta = 0; 2257 2258 for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) { 2259 acc->tcc.macc_table.entries[i].a = 1024; 2260 acc->tcc.macc_table.entries[i].b = 0; 2261 acc->tcc.macc_table.entries[i].c = 0; 2262 acc->tcc.macc_table.entries[i].d = 1024; 2263 } 2264 2265 acc->tcc.inv_y_lut.entries[6] = 1023; 2266 for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++) 2267 acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6); 2268 2269 acc->tcc.gain_pcwl = imgu_css_tcc_gain_pcwl_lut; 2270 acc->tcc.r_sqr_lut = imgu_css_tcc_r_sqr_lut; 2271 } 2272 2273 /* acc_param: dpc_config */ 2274 2275 if (use && use->acc_dpc) 2276 return -EINVAL; /* Not supported yet */ 2277 2278 /* Just disable by default */ 2279 memset(&acc->dpc, 0, sizeof(acc->dpc)); 2280 2281 /* acc_param: bds_config */ 2282 2283 bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height * 2284 IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2285 if (bds_ds < IMGU_BDS_MIN_SF_INV || 2286 bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(imgu_css_bds_configs)) 2287 return -EINVAL; 2288 2289 cfg_bds = &imgu_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV]; 2290 acc->bds.hor.hor_ctrl1.hor_crop_en = 0; 2291 acc->bds.hor.hor_ctrl1.hor_crop_start = 0; 2292 acc->bds.hor.hor_ctrl1.hor_crop_end = 0; 2293 acc->bds.hor.hor_ctrl0.sample_patrn_length = 2294 cfg_bds->sample_patrn_length; 2295 acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en; 2296 acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL; 2297 acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL; 2298 acc->bds.hor.hor_ctrl0.out_frame_width = 2299 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 2300 acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr; 2301 acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr; 2302 acc->bds.hor.hor_ctrl2.input_frame_height = 2303 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height; 2304 acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL; 2305 acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL; 2306 acc->bds.ver.ver_ctrl0.sample_patrn_length = 2307 cfg_bds->sample_patrn_length; 2308 acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en; 2309 acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr; 2310 acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr; 2311 acc->bds.ver.ver_ctrl1.out_frame_width = 2312 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 2313 acc->bds.ver.ver_ctrl1.out_frame_height = 2314 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2315 for (i = 0; i < stripes; i++) 2316 acc_bds_per_stripe_data(css, acc, i, pipe); 2317 2318 acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en; 2319 2320 /* acc_param: anr_config */ 2321 2322 if (use && use->acc_anr) { 2323 /* Take values from user */ 2324 acc->anr.transform = acc_user->anr.transform; 2325 acc->anr.stitch.anr_stitch_en = 2326 acc_user->anr.stitch.anr_stitch_en; 2327 memcpy(acc->anr.stitch.pyramid, acc_user->anr.stitch.pyramid, 2328 sizeof(acc->anr.stitch.pyramid)); 2329 } else if (acc_old) { 2330 /* Use old value */ 2331 acc->anr.transform = acc_old->anr.transform; 2332 acc->anr.stitch.anr_stitch_en = 2333 acc_old->anr.stitch.anr_stitch_en; 2334 memcpy(acc->anr.stitch.pyramid, acc_old->anr.stitch.pyramid, 2335 sizeof(acc->anr.stitch.pyramid)); 2336 } else { 2337 /* Calculate from scratch */ 2338 acc->anr = imgu_css_anr_defaults; 2339 } 2340 2341 /* Always enabled */ 2342 acc->anr.search.enable = 1; 2343 acc->anr.transform.enable = 1; 2344 acc->anr.tile2strm.enable = 1; 2345 acc->anr.tile2strm.frame_width = 2346 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN); 2347 acc->anr.search.frame_width = acc->anr.tile2strm.frame_width; 2348 acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width; 2349 acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2350 acc->anr.search.frame_height = acc->anr.tile2strm.frame_height; 2351 acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height; 2352 2353 width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN); 2354 height = css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2355 2356 if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET) 2357 acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width; 2358 if (acc->anr.transform.xreset < IPU3_UAPI_ANR_MIN_RESET) 2359 acc->anr.transform.xreset = IPU3_UAPI_ANR_MIN_RESET; 2360 2361 if (acc->anr.transform.yreset + height > IPU3_UAPI_ANR_MAX_RESET) 2362 acc->anr.transform.yreset = IPU3_UAPI_ANR_MAX_RESET - height; 2363 if (acc->anr.transform.yreset < IPU3_UAPI_ANR_MIN_RESET) 2364 acc->anr.transform.yreset = IPU3_UAPI_ANR_MIN_RESET; 2365 2366 /* acc_param: awb_fr_config */ 2367 2368 if (use && use->acc_awb_fr) { 2369 /* Take values from user */ 2370 acc->awb_fr.config = acc_user->awb_fr; 2371 } else if (acc_old) { 2372 /* Use old value */ 2373 acc->awb_fr.config = acc_old->awb_fr.config; 2374 } else { 2375 /* Set from scratch */ 2376 acc->awb_fr.config = imgu_css_awb_fr_defaults; 2377 } 2378 2379 imgu_css_grid_end_calc(&acc->awb_fr.config.grid_cfg); 2380 2381 if (acc->awb_fr.config.grid_cfg.width <= 0) 2382 return -EINVAL; 2383 2384 acc->awb_fr.config.grid_cfg.height_per_slice = 2385 IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET / 2386 acc->awb_fr.config.grid_cfg.width; 2387 2388 for (i = 0; i < stripes; i++) 2389 acc->awb_fr.stripes[i] = acc->awb_fr.config; 2390 2391 if (acc->awb_fr.config.grid_cfg.x_start >= 2392 acc->stripe.down_scaled_stripes[1].offset + min_overlap) { 2393 /* Enable only for rightmost stripe, disable left */ 2394 acc->awb_fr.stripes[0].grid_cfg.y_start &= 2395 ~IPU3_UAPI_GRID_Y_START_EN; 2396 } else if (acc->awb_fr.config.grid_cfg.x_end <= 2397 acc->stripe.bds_out_stripes[0].width - min_overlap) { 2398 /* Enable only for leftmost stripe, disable right */ 2399 acc->awb_fr.stripes[1].grid_cfg.y_start &= 2400 ~IPU3_UAPI_GRID_Y_START_EN; 2401 } else { 2402 /* Enable for both stripes */ 2403 u16 end; /* width for grid end */ 2404 2405 acc->awb_fr.stripes[0].grid_cfg.width = 2406 (acc->stripe.bds_out_stripes[0].width - min_overlap - 2407 acc->awb_fr.config.grid_cfg.x_start + 1) >> 2408 acc->awb_fr.config.grid_cfg.block_width_log2; 2409 acc->awb_fr.stripes[1].grid_cfg.width = 2410 acc->awb_fr.config.grid_cfg.width - 2411 acc->awb_fr.stripes[0].grid_cfg.width; 2412 2413 b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2; 2414 end = imgu_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start, 2415 acc->awb_fr.stripes[0].grid_cfg.width, 2416 b_w_log2); 2417 acc->awb_fr.stripes[0].grid_cfg.x_end = end; 2418 2419 acc->awb_fr.stripes[1].grid_cfg.x_start = 2420 (acc->awb_fr.stripes[0].grid_cfg.x_end + 1 - 2421 acc->stripe.down_scaled_stripes[1].offset) & 2422 IPU3_UAPI_GRID_START_MASK; 2423 b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2; 2424 end = imgu_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start, 2425 acc->awb_fr.stripes[1].grid_cfg.width, 2426 b_w_log2); 2427 acc->awb_fr.stripes[1].grid_cfg.x_end = end; 2428 2429 /* 2430 * To reduce complexity of debubbling and loading 2431 * statistics fix grid_height_per_slice to 1 for both 2432 * stripes. 2433 */ 2434 for (i = 0; i < stripes; i++) 2435 acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1; 2436 } 2437 2438 if (imgu_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr)) 2439 return -EINVAL; 2440 2441 /* acc_param: ae_config */ 2442 2443 if (use && use->acc_ae) { 2444 /* Take values from user */ 2445 acc->ae.grid_cfg = acc_user->ae.grid_cfg; 2446 acc->ae.ae_ccm = acc_user->ae.ae_ccm; 2447 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++) 2448 acc->ae.weights[i] = acc_user->ae.weights[i]; 2449 } else if (acc_old) { 2450 /* Use old value */ 2451 acc->ae.grid_cfg = acc_old->ae.grid_cfg; 2452 acc->ae.ae_ccm = acc_old->ae.ae_ccm; 2453 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++) 2454 acc->ae.weights[i] = acc_old->ae.weights[i]; 2455 } else { 2456 /* Set from scratch */ 2457 static const struct ipu3_uapi_ae_weight_elem 2458 weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 }; 2459 2460 acc->ae.grid_cfg = imgu_css_ae_grid_defaults; 2461 acc->ae.ae_ccm = imgu_css_ae_ccm_defaults; 2462 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++) 2463 acc->ae.weights[i] = weight_def; 2464 } 2465 2466 b_w_log2 = acc->ae.grid_cfg.block_width_log2; 2467 acc->ae.grid_cfg.x_end = imgu_css_grid_end(acc->ae.grid_cfg.x_start, 2468 acc->ae.grid_cfg.width, 2469 b_w_log2); 2470 b_w_log2 = acc->ae.grid_cfg.block_height_log2; 2471 acc->ae.grid_cfg.y_end = imgu_css_grid_end(acc->ae.grid_cfg.y_start, 2472 acc->ae.grid_cfg.height, 2473 b_w_log2); 2474 2475 for (i = 0; i < stripes; i++) 2476 acc->ae.stripes[i].grid = acc->ae.grid_cfg; 2477 2478 if (acc->ae.grid_cfg.x_start >= 2479 acc->stripe.down_scaled_stripes[1].offset) { 2480 /* Enable only for rightmost stripe, disable left */ 2481 acc->ae.stripes[0].grid.ae_en = 0; 2482 } else if (acc->ae.grid_cfg.x_end <= 2483 acc->stripe.bds_out_stripes[0].width) { 2484 /* Enable only for leftmost stripe, disable right */ 2485 acc->ae.stripes[1].grid.ae_en = 0; 2486 } else { 2487 /* Enable for both stripes */ 2488 u8 b_w_log2; 2489 2490 acc->ae.stripes[0].grid.width = 2491 (acc->stripe.bds_out_stripes[0].width - 2492 acc->ae.grid_cfg.x_start + 1) >> 2493 acc->ae.grid_cfg.block_width_log2; 2494 2495 acc->ae.stripes[1].grid.width = 2496 acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width; 2497 2498 b_w_log2 = acc->ae.stripes[0].grid.block_width_log2; 2499 acc->ae.stripes[0].grid.x_end = 2500 imgu_css_grid_end(acc->ae.stripes[0].grid.x_start, 2501 acc->ae.stripes[0].grid.width, 2502 b_w_log2); 2503 2504 acc->ae.stripes[1].grid.x_start = 2505 (acc->ae.stripes[0].grid.x_end + 1 - 2506 acc->stripe.down_scaled_stripes[1].offset) & 2507 IPU3_UAPI_GRID_START_MASK; 2508 b_w_log2 = acc->ae.stripes[1].grid.block_width_log2; 2509 acc->ae.stripes[1].grid.x_end = 2510 imgu_css_grid_end(acc->ae.stripes[1].grid.x_start, 2511 acc->ae.stripes[1].grid.width, 2512 b_w_log2); 2513 } 2514 2515 /* acc_param: af_config */ 2516 2517 if (use && use->acc_af) { 2518 /* Take values from user */ 2519 acc->af.config.filter_config = acc_user->af.filter_config; 2520 acc->af.config.grid_cfg = acc_user->af.grid_cfg; 2521 } else if (acc_old) { 2522 /* Use old value */ 2523 acc->af.config = acc_old->af.config; 2524 } else { 2525 /* Set from scratch */ 2526 acc->af.config.filter_config = 2527 imgu_css_af_defaults.filter_config; 2528 acc->af.config.grid_cfg = imgu_css_af_defaults.grid_cfg; 2529 } 2530 2531 imgu_css_grid_end_calc(&acc->af.config.grid_cfg); 2532 2533 if (acc->af.config.grid_cfg.width <= 0) 2534 return -EINVAL; 2535 2536 acc->af.config.grid_cfg.height_per_slice = 2537 IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width; 2538 acc->af.config.frame_size.width = 2539 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN); 2540 acc->af.config.frame_size.height = 2541 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2542 2543 if (acc->stripe.bds_out_stripes[0].width <= min_overlap) 2544 return -EINVAL; 2545 2546 for (i = 0; i < stripes; i++) { 2547 acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg; 2548 acc->af.stripes[i].frame_size.height = 2549 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2550 acc->af.stripes[i].frame_size.width = 2551 acc->stripe.bds_out_stripes[i].width; 2552 } 2553 2554 if (acc->af.config.grid_cfg.x_start >= 2555 acc->stripe.down_scaled_stripes[1].offset + min_overlap) { 2556 /* Enable only for rightmost stripe, disable left */ 2557 acc->af.stripes[0].grid_cfg.y_start &= 2558 ~IPU3_UAPI_GRID_Y_START_EN; 2559 acc->af.stripes[1].grid_cfg.x_start = 2560 (acc->af.stripes[1].grid_cfg.x_start - 2561 acc->stripe.down_scaled_stripes[1].offset) & 2562 IPU3_UAPI_GRID_START_MASK; 2563 b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2; 2564 acc->af.stripes[1].grid_cfg.x_end = 2565 imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start, 2566 acc->af.stripes[1].grid_cfg.width, 2567 b_w_log2); 2568 } else if (acc->af.config.grid_cfg.x_end <= 2569 acc->stripe.bds_out_stripes[0].width - min_overlap) { 2570 /* Enable only for leftmost stripe, disable right */ 2571 acc->af.stripes[1].grid_cfg.y_start &= 2572 ~IPU3_UAPI_GRID_Y_START_EN; 2573 } else { 2574 /* Enable for both stripes */ 2575 2576 acc->af.stripes[0].grid_cfg.width = 2577 (acc->stripe.bds_out_stripes[0].width - min_overlap - 2578 acc->af.config.grid_cfg.x_start + 1) >> 2579 acc->af.config.grid_cfg.block_width_log2; 2580 acc->af.stripes[1].grid_cfg.width = 2581 acc->af.config.grid_cfg.width - 2582 acc->af.stripes[0].grid_cfg.width; 2583 2584 b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2; 2585 acc->af.stripes[0].grid_cfg.x_end = 2586 imgu_css_grid_end(acc->af.stripes[0].grid_cfg.x_start, 2587 acc->af.stripes[0].grid_cfg.width, 2588 b_w_log2); 2589 2590 acc->af.stripes[1].grid_cfg.x_start = 2591 (acc->af.stripes[0].grid_cfg.x_end + 1 - 2592 acc->stripe.down_scaled_stripes[1].offset) & 2593 IPU3_UAPI_GRID_START_MASK; 2594 2595 b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2; 2596 acc->af.stripes[1].grid_cfg.x_end = 2597 imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start, 2598 acc->af.stripes[1].grid_cfg.width, 2599 b_w_log2); 2600 2601 /* 2602 * To reduce complexity of debubbling and loading statistics 2603 * fix grid_height_per_slice to 1 for both stripes 2604 */ 2605 for (i = 0; i < stripes; i++) 2606 acc->af.stripes[i].grid_cfg.height_per_slice = 1; 2607 } 2608 2609 if (imgu_css_af_ops_calc(css, pipe, &acc->af)) 2610 return -EINVAL; 2611 2612 /* acc_param: awb_config */ 2613 2614 if (use && use->acc_awb) { 2615 /* Take values from user */ 2616 acc->awb.config = acc_user->awb.config; 2617 } else if (acc_old) { 2618 /* Use old value */ 2619 acc->awb.config = acc_old->awb.config; 2620 } else { 2621 /* Set from scratch */ 2622 acc->awb.config = imgu_css_awb_defaults; 2623 } 2624 2625 if (acc->awb.config.grid.width <= 0) 2626 return -EINVAL; 2627 2628 acc->awb.config.grid.height_per_slice = 2629 IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width, 2630 imgu_css_grid_end_calc(&acc->awb.config.grid); 2631 2632 for (i = 0; i < stripes; i++) 2633 acc->awb.stripes[i] = acc->awb.config; 2634 2635 if (acc->awb.config.grid.x_start >= 2636 acc->stripe.down_scaled_stripes[1].offset + min_overlap) { 2637 /* Enable only for rightmost stripe, disable left */ 2638 acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN; 2639 2640 acc->awb.stripes[1].grid.x_start = 2641 (acc->awb.stripes[1].grid.x_start - 2642 acc->stripe.down_scaled_stripes[1].offset) & 2643 IPU3_UAPI_GRID_START_MASK; 2644 2645 b_w_log2 = acc->awb.stripes[1].grid.block_width_log2; 2646 acc->awb.stripes[1].grid.x_end = 2647 imgu_css_grid_end(acc->awb.stripes[1].grid.x_start, 2648 acc->awb.stripes[1].grid.width, 2649 b_w_log2); 2650 } else if (acc->awb.config.grid.x_end <= 2651 acc->stripe.bds_out_stripes[0].width - min_overlap) { 2652 /* Enable only for leftmost stripe, disable right */ 2653 acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN; 2654 } else { 2655 /* Enable for both stripes */ 2656 2657 acc->awb.stripes[0].grid.width = 2658 (acc->stripe.bds_out_stripes[0].width - 2659 acc->awb.config.grid.x_start + 1) >> 2660 acc->awb.config.grid.block_width_log2; 2661 acc->awb.stripes[1].grid.width = acc->awb.config.grid.width - 2662 acc->awb.stripes[0].grid.width; 2663 2664 b_w_log2 = acc->awb.stripes[0].grid.block_width_log2; 2665 acc->awb.stripes[0].grid.x_end = 2666 imgu_css_grid_end(acc->awb.stripes[0].grid.x_start, 2667 acc->awb.stripes[0].grid.width, 2668 b_w_log2); 2669 2670 acc->awb.stripes[1].grid.x_start = 2671 (acc->awb.stripes[0].grid.x_end + 1 - 2672 acc->stripe.down_scaled_stripes[1].offset) & 2673 IPU3_UAPI_GRID_START_MASK; 2674 2675 b_w_log2 = acc->awb.stripes[1].grid.block_width_log2; 2676 acc->awb.stripes[1].grid.x_end = 2677 imgu_css_grid_end(acc->awb.stripes[1].grid.x_start, 2678 acc->awb.stripes[1].grid.width, 2679 b_w_log2); 2680 2681 /* 2682 * To reduce complexity of debubbling and loading statistics 2683 * fix grid_height_per_slice to 1 for both stripes 2684 */ 2685 for (i = 0; i < stripes; i++) 2686 acc->awb.stripes[i].grid.height_per_slice = 1; 2687 } 2688 2689 if (imgu_css_awb_ops_calc(css, pipe, &acc->awb)) 2690 return -EINVAL; 2691 2692 return 0; 2693} 2694 2695/* 2696 * Fill the indicated structure in `new_binary_params' from the possible 2697 * sources based on `use_user' flag: if the flag is false, copy from 2698 * `old_binary_params', or if the flag is true, copy from `user_setting' 2699 * and return NULL (or error pointer on error). 2700 * If the flag is false and `old_binary_params' is NULL, return pointer 2701 * to the structure inside `new_binary_params'. In that case the caller 2702 * should calculate and fill the structure from scratch. 2703 */ 2704static void *imgu_css_cfg_copy(struct imgu_css *css, 2705 unsigned int pipe, bool use_user, 2706 void *user_setting, void *old_binary_params, 2707 void *new_binary_params, 2708 enum imgu_abi_memories m, 2709 struct imgu_fw_isp_parameter *par, 2710 size_t par_size) 2711{ 2712 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM; 2713 void *new_setting, *old_setting; 2714 2715 new_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par, 2716 par_size, new_binary_params); 2717 if (!new_setting) 2718 return ERR_PTR(-EPROTO); /* Corrupted firmware */ 2719 2720 if (use_user) { 2721 /* Take new user parameters */ 2722 memcpy(new_setting, user_setting, par_size); 2723 } else if (old_binary_params) { 2724 /* Take previous value */ 2725 old_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par, 2726 par_size, 2727 old_binary_params); 2728 if (!old_setting) 2729 return ERR_PTR(-EPROTO); 2730 memcpy(new_setting, old_setting, par_size); 2731 } else { 2732 return new_setting; /* Need to calculate */ 2733 } 2734 2735 return NULL; /* Copied from other value */ 2736} 2737 2738/* 2739 * Configure VMEM0 parameters (late binding parameters). 2740 */ 2741int imgu_css_cfg_vmem0(struct imgu_css *css, unsigned int pipe, 2742 struct ipu3_uapi_flags *use, 2743 void *vmem0, void *vmem0_old, 2744 struct ipu3_uapi_params *user) 2745{ 2746 const struct imgu_fw_info *bi = 2747 &css->fwp->binary_header[css->pipes[pipe].bindex]; 2748 struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp + 2749 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]; 2750 struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL; 2751 struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem = NULL; 2752 struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem = NULL; 2753 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM; 2754 const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0; 2755 unsigned int i; 2756 2757 /* Configure VMEM0 */ 2758 2759 memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size); 2760 2761 /* Configure Linearization VMEM0 parameters */ 2762 2763 lin_vmem = imgu_css_cfg_copy(css, pipe, use && use->lin_vmem_params, 2764 &user->lin_vmem_params, vmem0_old, vmem0, 2765 m, &pofs->vmem.lin, sizeof(*lin_vmem)); 2766 if (!IS_ERR_OR_NULL(lin_vmem)) { 2767 /* Generate parameter from scratch */ 2768 for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) { 2769 lin_vmem->lin_lutlow_gr[i] = 32 * i; 2770 lin_vmem->lin_lutlow_r[i] = 32 * i; 2771 lin_vmem->lin_lutlow_b[i] = 32 * i; 2772 lin_vmem->lin_lutlow_gb[i] = 32 * i; 2773 2774 lin_vmem->lin_lutdif_gr[i] = 32; 2775 lin_vmem->lin_lutdif_r[i] = 32; 2776 lin_vmem->lin_lutdif_b[i] = 32; 2777 lin_vmem->lin_lutdif_gb[i] = 32; 2778 } 2779 } 2780 2781 /* Configure TNR3 VMEM parameters */ 2782 if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) { 2783 tnr_vmem = imgu_css_cfg_copy(css, pipe, 2784 use && use->tnr3_vmem_params, 2785 &user->tnr3_vmem_params, 2786 vmem0_old, vmem0, m, 2787 &pofs->vmem.tnr3, 2788 sizeof(*tnr_vmem)); 2789 if (!IS_ERR_OR_NULL(tnr_vmem)) { 2790 /* Generate parameter from scratch */ 2791 for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++) 2792 tnr_vmem->sigma[i] = 256; 2793 } 2794 } 2795 i = IPU3_UAPI_ISP_TNR3_VMEM_LEN; 2796 2797 /* Configure XNR3 VMEM parameters */ 2798 2799 xnr_vmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params, 2800 &user->xnr3_vmem_params, vmem0_old, vmem0, 2801 m, &pofs->vmem.xnr3, sizeof(*xnr_vmem)); 2802 if (!IS_ERR_OR_NULL(xnr_vmem)) { 2803 xnr_vmem->x[i] = imgu_css_xnr3_vmem_defaults.x 2804 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2805 xnr_vmem->a[i] = imgu_css_xnr3_vmem_defaults.a 2806 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2807 xnr_vmem->b[i] = imgu_css_xnr3_vmem_defaults.b 2808 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2809 xnr_vmem->c[i] = imgu_css_xnr3_vmem_defaults.c 2810 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2811 } 2812 2813 return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ? 2814 -EPROTO : 0; 2815} 2816 2817/* 2818 * Configure DMEM0 parameters (late binding parameters). 2819 */ 2820int imgu_css_cfg_dmem0(struct imgu_css *css, unsigned int pipe, 2821 struct ipu3_uapi_flags *use, 2822 void *dmem0, void *dmem0_old, 2823 struct ipu3_uapi_params *user) 2824{ 2825 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 2826 const struct imgu_fw_info *bi = 2827 &css->fwp->binary_header[css_pipe->bindex]; 2828 struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp + 2829 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]; 2830 2831 struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL; 2832 struct ipu3_uapi_isp_xnr3_params *xnr_dmem; 2833 2834 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM; 2835 const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0; 2836 2837 /* Configure DMEM0 */ 2838 2839 memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size); 2840 2841 /* Configure TNR3 DMEM0 parameters */ 2842 if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) { 2843 tnr_dmem = imgu_css_cfg_copy(css, pipe, 2844 use && use->tnr3_dmem_params, 2845 &user->tnr3_dmem_params, 2846 dmem0_old, dmem0, m, 2847 &pofs->dmem.tnr3, 2848 sizeof(*tnr_dmem)); 2849 if (!IS_ERR_OR_NULL(tnr_dmem)) { 2850 /* Generate parameter from scratch */ 2851 tnr_dmem->knee_y1 = 768; 2852 tnr_dmem->knee_y2 = 1280; 2853 } 2854 } 2855 2856 /* Configure XNR3 DMEM0 parameters */ 2857 2858 xnr_dmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params, 2859 &user->xnr3_dmem_params, dmem0_old, dmem0, 2860 m, &pofs->dmem.xnr3, sizeof(*xnr_dmem)); 2861 if (!IS_ERR_OR_NULL(xnr_dmem)) { 2862 /* Generate parameter from scratch */ 2863 xnr_dmem->alpha.y0 = 2047; 2864 xnr_dmem->alpha.u0 = 2047; 2865 xnr_dmem->alpha.v0 = 2047; 2866 } 2867 2868 return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0; 2869} 2870 2871/* Generate unity morphing table without morphing effect */ 2872void imgu_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc, 2873 int frame_in_x, int frame_in_y, 2874 int frame_out_x, int frame_out_y, 2875 int env_w, int env_h) 2876{ 2877 static const unsigned int FRAC_BITS = IMGU_ABI_GDC_FRAC_BITS; 2878 static const unsigned int XMEM_ALIGN = 1 << 4; 2879 const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1); 2880 static const unsigned int BCI_ENV = 4; 2881 static const unsigned int BYP = 2; /* Bytes per pixel */ 2882 const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + env_w + 1; 2883 const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + env_h + 1; 2884 2885 struct imgu_abi_gdc_warp_param gdc_luma, gdc_chroma; 2886 2887 unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x, 2888 IMGU_DVS_BLOCK_W), 2); 2889 unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H); 2890 unsigned int y0, x0, x1, x, y; 2891 2892 /* Global luma settings */ 2893 gdc_luma.origin_x = 0; 2894 gdc_luma.origin_y = 0; 2895 gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << FRAC_BITS; 2896 gdc_luma.p0_y = 0; 2897 gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS); 2898 gdc_luma.p1_y = gdc_luma.p0_y; 2899 gdc_luma.p2_x = gdc_luma.p0_x; 2900 gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << FRAC_BITS); 2901 gdc_luma.p3_x = gdc_luma.p1_x; 2902 gdc_luma.p3_y = gdc_luma.p2_y; 2903 2904 gdc_luma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV + 2905 OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK); 2906 gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width, 2907 IPU3_UAPI_ISP_VEC_ELEMS); 2908 gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width, 2909 IMGU_ABI_ISP_DDR_WORD_BYTES / 2910 BYP); 2911 gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV; 2912 gdc_luma.padding = 0; 2913 2914 /* Global chroma settings */ 2915 gdc_chroma.origin_x = 0; 2916 gdc_chroma.origin_y = 0; 2917 gdc_chroma.p0_x = (OFFSET_X / 2 - (OFFSET_X / 2 & XMEM_ALIGN_MASK)) << 2918 FRAC_BITS; 2919 gdc_chroma.p0_y = 0; 2920 gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS); 2921 gdc_chroma.p1_y = gdc_chroma.p0_y; 2922 gdc_chroma.p2_x = gdc_chroma.p0_x; 2923 gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << FRAC_BITS); 2924 gdc_chroma.p3_x = gdc_chroma.p1_x; 2925 gdc_chroma.p3_y = gdc_chroma.p2_y; 2926 2927 gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV; 2928 gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width, 2929 IPU3_UAPI_ISP_VEC_ELEMS); 2930 gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width, 2931 IMGU_ABI_ISP_DDR_WORD_BYTES / 2932 BYP); 2933 gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV; 2934 gdc_chroma.padding = 0; 2935 2936 /* Calculate block offsets for luma and chroma */ 2937 for (y0 = 0; y0 < blocks_y; y0++) { 2938 for (x0 = 0; x0 < blocks_x / 2; x0++) { 2939 for (x1 = 0; x1 < 2; x1++) { 2940 /* Luma blocks */ 2941 x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X; 2942 x &= XMEM_ALIGN_MASK; 2943 y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y; 2944 *gdc = gdc_luma; 2945 gdc->in_addr_offset = 2946 (y * frame_in_x + x) * BYP; 2947 gdc++; 2948 } 2949 2950 /* Chroma block */ 2951 x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2; 2952 x &= XMEM_ALIGN_MASK; 2953 y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2; 2954 *gdc = gdc_chroma; 2955 gdc->in_addr_offset = (y * frame_in_x + x) * BYP; 2956 gdc++; 2957 } 2958 } 2959}