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 17 struct 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 28 static 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 */ 43 static void 44 imgu_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 */ 114 static unsigned int 115 imgu_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 */ 133 static void 134 imgu_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 195 static 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 */ 232 static 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 */ 246 static 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 */ 263 static 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 */ 280 static 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 293 struct 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 307 struct 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 323 struct 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 */ 360 static 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 int pin_scale = 0; 775 /*Input resolution */ 776 777 stripe_params[s].input_width = stripe_input_width_y; 778 stripe_params[s].input_height = reso.input_height; 779 780 for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) { 781 if (frame_params[i].scaled) { 782 /* 783 * Output stripe resolution and offset 784 * as produced by the scaler; actual 785 * output resolution may be slightly 786 * smaller. 787 */ 788 stripe_params[s].output_width[i] = 789 stripe_output_width_y; 790 stripe_params[s].output_height[i] = 791 reso.pin_height[i]; 792 stripe_params[s].output_offset[i] = 793 stripe_offset_out_y; 794 795 pin_scale += frame_params[i].scaled; 796 } else { 797 /* Unscaled pin */ 798 stripe_params[s].output_width[i] = 799 stripe_params[s].input_width; 800 stripe_params[s].output_height[i] = 801 stripe_params[s].input_height; 802 stripe_params[s].output_offset[i] = 803 stripe_offset_blk_y; 804 } 805 } 806 807 /* If no pin use scale, we use BYPASS mode */ 808 stripe_params[s].processing_mode = procmode; 809 stripe_params[s].phase_step = scaler_luma->phase_step; 810 stripe_params[s].exp_shift = scaler_luma->exp_shift; 811 stripe_params[s].phase_init_left_y = 812 stripe_phase_init_y; 813 stripe_params[s].phase_init_left_uv = 814 stripe_phase_init_uv; 815 stripe_params[s].phase_init_top_y = 816 scaler_luma->phase_init; 817 stripe_params[s].phase_init_top_uv = 818 scaler_chroma->phase_init; 819 stripe_params[s].pad_left_y = stripe_pad_left_y; 820 stripe_params[s].pad_left_uv = stripe_pad_left_uv; 821 stripe_params[s].pad_right_y = stripe_pad_right_y; 822 stripe_params[s].pad_right_uv = stripe_pad_right_uv; 823 stripe_params[s].pad_top_y = scaler_luma->pad_left; 824 stripe_params[s].pad_top_uv = scaler_chroma->pad_left; 825 stripe_params[s].pad_bottom_y = scaler_luma->pad_right; 826 stripe_params[s].pad_bottom_uv = 827 scaler_chroma->pad_right; 828 stripe_params[s].crop_left_y = stripe_crop_left_y; 829 stripe_params[s].crop_top_y = scaler_luma->crop_top; 830 stripe_params[s].crop_left_uv = stripe_crop_left_uv; 831 stripe_params[s].crop_top_uv = scaler_chroma->crop_top; 832 stripe_params[s].start_column_y = stripe_offset_col_y; 833 stripe_params[s].start_column_uv = stripe_offset_col_uv; 834 stripe_params[s].chunk_width = reso.chunk_width; 835 stripe_params[s].chunk_height = reso.chunk_height; 836 stripe_params[s].block_width = reso.block_width; 837 stripe_params[s].block_height = reso.block_height; 838 } 839 } 840 841 return 0; 842 } 843 844 /* 845 * This function configures the Output Formatter System, given the number of 846 * stripes, scaler luma and chrome parameters 847 */ 848 static int imgu_css_osys_calc(struct imgu_css *css, unsigned int pipe, 849 unsigned int stripes, 850 struct imgu_abi_osys_config *osys, 851 struct imgu_css_scaler_info *scaler_luma, 852 struct imgu_css_scaler_info *scaler_chroma, 853 struct imgu_abi_stripes block_stripes[]) 854 { 855 struct imgu_css_frame_params frame_params[IMGU_ABI_OSYS_PINS]; 856 struct imgu_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES]; 857 struct imgu_abi_osys_formatter_params *param; 858 unsigned int pin, s; 859 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 860 861 memset(osys, 0, sizeof(*osys)); 862 863 /* Compute the frame and stripe params */ 864 if (imgu_css_osys_calc_frame_and_stripe_params(css, stripes, osys, 865 scaler_luma, 866 scaler_chroma, 867 frame_params, 868 stripe_params, pipe)) 869 return -EINVAL; 870 871 /* Output formatter system parameters */ 872 873 for (s = 0; s < stripes; s++) { 874 struct imgu_abi_osys_scaler_params *scaler = 875 &osys->scaler[s].param; 876 int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT; 877 int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP; 878 879 /* OUTPUT 0 / PIN 0 is only Scaler output */ 880 scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR; 881 882 /* 883 * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC) 884 * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) / 885 * (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS) 886 * = 2 * 64 / 32 = 4 887 */ 888 scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE; 889 /* 890 * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size) 891 * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) + 892 * (VMEM1_y_size / 4) 893 * = (VMEM1_y_size) + (VMEM1_y_size / 4) + 894 * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4 895 * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE) 896 */ 897 scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE; 898 scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 899 IMGU_VMEM1_U_OFFSET; 900 scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 901 IMGU_VMEM1_V_OFFSET; 902 scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE; 903 scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE; 904 scaler->inp_buf_chunk_width = stripe_params[s].chunk_width; 905 scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS; 906 907 /* Output buffers */ 908 scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR; 909 scaler->out_buf_y_line_stride = stripe_params[s].block_width / 910 IMGU_VMEM1_ELEMS_PER_VEC; 911 scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE; 912 scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 913 IMGU_VMEM1_U_OFFSET; 914 scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 915 IMGU_VMEM1_V_OFFSET; 916 scaler->out_buf_uv_line_stride = stripe_params[s].block_width / 917 IMGU_VMEM1_ELEMS_PER_VEC / 2; 918 scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE; 919 scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS; 920 921 /* Intermediate buffers */ 922 scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR; 923 scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE; 924 scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR; 925 scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR; 926 scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE; 927 scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK; 928 scaler->int_buf_chunk_width = stripe_params[s].chunk_height; 929 scaler->int_buf_chunk_height = stripe_params[s].block_width; 930 931 /* Context buffers */ 932 scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR; 933 scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR; 934 scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR; 935 scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR; 936 scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR; 937 scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR; 938 939 /* Addresses for release-input and process-output tokens */ 940 scaler->release_inp_buf_addr = fifo_addr_ack; 941 scaler->release_inp_buf_en = 1; 942 scaler->release_out_buf_en = 1; 943 scaler->process_out_buf_addr = fifo_addr_fmt; 944 945 /* Settings dimensions, padding, cropping */ 946 scaler->input_image_y_width = stripe_params[s].input_width; 947 scaler->input_image_y_height = stripe_params[s].input_height; 948 scaler->input_image_y_start_column = 949 stripe_params[s].start_column_y; 950 scaler->input_image_uv_start_column = 951 stripe_params[s].start_column_uv; 952 scaler->input_image_y_left_pad = stripe_params[s].pad_left_y; 953 scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv; 954 scaler->input_image_y_right_pad = stripe_params[s].pad_right_y; 955 scaler->input_image_uv_right_pad = 956 stripe_params[s].pad_right_uv; 957 scaler->input_image_y_top_pad = stripe_params[s].pad_top_y; 958 scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv; 959 scaler->input_image_y_bottom_pad = 960 stripe_params[s].pad_bottom_y; 961 scaler->input_image_uv_bottom_pad = 962 stripe_params[s].pad_bottom_uv; 963 scaler->processing_mode = stripe_params[s].processing_mode; 964 scaler->scaling_ratio = stripe_params[s].phase_step; 965 scaler->y_left_phase_init = stripe_params[s].phase_init_left_y; 966 scaler->uv_left_phase_init = 967 stripe_params[s].phase_init_left_uv; 968 scaler->y_top_phase_init = stripe_params[s].phase_init_top_y; 969 scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv; 970 scaler->coeffs_exp_shift = stripe_params[s].exp_shift; 971 scaler->out_y_left_crop = stripe_params[s].crop_left_y; 972 scaler->out_uv_left_crop = stripe_params[s].crop_left_uv; 973 scaler->out_y_top_crop = stripe_params[s].crop_top_y; 974 scaler->out_uv_top_crop = stripe_params[s].crop_top_uv; 975 976 for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) { 977 int in_fifo_addr; 978 int out_fifo_addr; 979 int block_width_vecs; 980 int input_width_s; 981 int input_width_vecs; 982 int input_buf_y_st_addr; 983 int input_buf_u_st_addr; 984 int input_buf_v_st_addr; 985 int input_buf_y_line_stride; 986 int input_buf_uv_line_stride; 987 int output_buf_y_line_stride; 988 int output_buf_uv_line_stride; 989 int output_buf_nr_y_lines; 990 int block_height; 991 int block_width; 992 struct imgu_abi_osys_frame_params *fr_pr; 993 994 fr_pr = &osys->frame[pin].param; 995 996 /* Frame parameters */ 997 fr_pr->enable = frame_params[pin].enable; 998 fr_pr->format = frame_params[pin].format; 999 fr_pr->mirror = frame_params[pin].mirror; 1000 fr_pr->flip = frame_params[pin].flip; 1001 fr_pr->tiling = frame_params[pin].tiling; 1002 fr_pr->width = frame_params[pin].width; 1003 fr_pr->height = frame_params[pin].height; 1004 fr_pr->stride = frame_params[pin].stride; 1005 fr_pr->scaled = frame_params[pin].scaled; 1006 1007 /* Stripe parameters */ 1008 osys->stripe[s].crop_top[pin] = 1009 frame_params[pin].crop_top; 1010 osys->stripe[s].input_width = 1011 stripe_params[s].input_width; 1012 osys->stripe[s].input_height = 1013 stripe_params[s].input_height; 1014 osys->stripe[s].block_height = 1015 stripe_params[s].block_height; 1016 osys->stripe[s].block_width = 1017 stripe_params[s].block_width; 1018 osys->stripe[s].output_width[pin] = 1019 stripe_params[s].output_width[pin]; 1020 osys->stripe[s].output_height[pin] = 1021 stripe_params[s].output_height[pin]; 1022 1023 if (s == 0) { 1024 /* Only first stripe should do left cropping */ 1025 osys->stripe[s].crop_left[pin] = 1026 frame_params[pin].crop_left; 1027 osys->stripe[s].output_offset[pin] = 1028 stripe_params[s].output_offset[pin]; 1029 } else { 1030 /* 1031 * Stripe offset for other strips should be 1032 * adjusted according to the cropping done 1033 * at the first strip 1034 */ 1035 osys->stripe[s].crop_left[pin] = 0; 1036 osys->stripe[s].output_offset[pin] = 1037 (stripe_params[s].output_offset[pin] - 1038 osys->stripe[0].crop_left[pin]); 1039 } 1040 1041 if (!frame_params[pin].enable) 1042 continue; 1043 1044 /* Formatter: configurations */ 1045 1046 /* 1047 * Get the dimensions of the input blocks of the 1048 * formatter, which is the same as the output 1049 * blocks of the scaler. 1050 */ 1051 if (frame_params[pin].scaled) { 1052 block_height = stripe_params[s].block_height; 1053 block_width = stripe_params[s].block_width; 1054 } else { 1055 block_height = IMGU_OSYS_BLOCK_HEIGHT; 1056 block_width = IMGU_OSYS_BLOCK_WIDTH; 1057 } 1058 block_width_vecs = 1059 block_width / IMGU_VMEM1_ELEMS_PER_VEC; 1060 /* 1061 * The input/output line stride depends on the 1062 * block size. 1063 */ 1064 input_buf_y_line_stride = block_width_vecs; 1065 input_buf_uv_line_stride = block_width_vecs / 2; 1066 output_buf_y_line_stride = block_width_vecs; 1067 output_buf_uv_line_stride = block_width_vecs / 2; 1068 output_buf_nr_y_lines = block_height; 1069 if (frame_params[pin].format == 1070 IMGU_ABI_OSYS_FORMAT_NV12 || 1071 frame_params[pin].format == 1072 IMGU_ABI_OSYS_FORMAT_NV21) 1073 output_buf_uv_line_stride = 1074 output_buf_y_line_stride; 1075 1076 /* 1077 * Tiled outputs use a different output buffer 1078 * configuration. The input (= scaler output) block 1079 * width translates to a tile height, and the block 1080 * height to the tile width. The default block size of 1081 * 128x32 maps exactly onto a 4kB tile (512x8) for Y. 1082 * For UV, the tile width is always half. 1083 */ 1084 if (frame_params[pin].tiling) { 1085 output_buf_nr_y_lines = 8; 1086 output_buf_y_line_stride = 512 / 1087 IMGU_VMEM1_ELEMS_PER_VEC; 1088 output_buf_uv_line_stride = 256 / 1089 IMGU_VMEM1_ELEMS_PER_VEC; 1090 } 1091 1092 /* 1093 * Store the output buffer line stride. Will be 1094 * used to compute buffer offsets in boundary 1095 * conditions when output blocks are partially 1096 * outside the image. 1097 */ 1098 osys->stripe[s].buf_stride[pin] = 1099 output_buf_y_line_stride * 1100 IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS; 1101 if (frame_params[pin].scaled) { 1102 /* 1103 * The input buffs are the intermediate 1104 * buffers (scalers' output) 1105 */ 1106 input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR; 1107 input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 1108 IMGU_VMEM1_U_OFFSET; 1109 input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR + 1110 IMGU_VMEM1_V_OFFSET; 1111 } else { 1112 /* 1113 * The input bufferss are the buffers 1114 * filled by the SP 1115 */ 1116 input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR; 1117 input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 1118 IMGU_VMEM1_U_OFFSET; 1119 input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR + 1120 IMGU_VMEM1_V_OFFSET; 1121 } 1122 1123 /* 1124 * The formatter input width must be rounded to 1125 * the block width. Otherwise the formatter will 1126 * not recognize the end of the line, resulting 1127 * in incorrect tiling (system may hang!) and 1128 * possibly other problems. 1129 */ 1130 input_width_s = 1131 roundup(stripe_params[s].output_width[pin], 1132 block_width); 1133 input_width_vecs = input_width_s / 1134 IMGU_VMEM1_ELEMS_PER_VEC; 1135 out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP; 1136 /* 1137 * Process-output tokens must be sent to the SP. 1138 * When scaling, the release-input tokens can be 1139 * sent directly to the scaler, otherwise the 1140 * formatter should send them to the SP. 1141 */ 1142 if (frame_params[pin].scaled) 1143 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER; 1144 else 1145 in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP; 1146 1147 /* Formatter */ 1148 param = &osys->formatter[s][pin].param; 1149 1150 param->format = frame_params[pin].format; 1151 param->flip = frame_params[pin].flip; 1152 param->mirror = frame_params[pin].mirror; 1153 param->tiling = frame_params[pin].tiling; 1154 param->reduce_range = frame_params[pin].reduce_range; 1155 param->alpha_blending = 0; 1156 param->release_inp_addr = in_fifo_addr; 1157 param->release_inp_en = 1; 1158 param->process_out_buf_addr = out_fifo_addr; 1159 param->image_width_vecs = input_width_vecs; 1160 param->image_height_lines = 1161 stripe_params[s].output_height[pin]; 1162 param->inp_buff_y_st_addr = input_buf_y_st_addr; 1163 param->inp_buff_y_line_stride = input_buf_y_line_stride; 1164 param->inp_buff_y_buffer_stride = IMGU_VMEM1_BUF_SIZE; 1165 param->int_buff_u_st_addr = input_buf_u_st_addr; 1166 param->int_buff_v_st_addr = input_buf_v_st_addr; 1167 param->inp_buff_uv_line_stride = 1168 input_buf_uv_line_stride; 1169 param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE; 1170 param->out_buff_level = 0; 1171 param->out_buff_nr_y_lines = output_buf_nr_y_lines; 1172 param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET; 1173 param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET; 1174 param->out_buff_y_line_stride = 1175 output_buf_y_line_stride; 1176 param->out_buff_uv_line_stride = 1177 output_buf_uv_line_stride; 1178 param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR; 1179 param->hist_buff_line_stride = 1180 IMGU_VMEM1_HST_BUF_STRIDE; 1181 param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES; 1182 } 1183 } 1184 1185 block_stripes[0].offset = 0; 1186 if (stripes <= 1) { 1187 block_stripes[0].width = stripe_params[0].input_width; 1188 block_stripes[0].height = stripe_params[0].input_height; 1189 } else { 1190 struct imgu_fw_info *bi = 1191 &css->fwp->binary_header[css_pipe->bindex]; 1192 unsigned int sp_block_width = 1193 bi->info.isp.sp.block.block_width * 1194 IPU3_UAPI_ISP_VEC_ELEMS; 1195 1196 block_stripes[0].width = roundup(stripe_params[0].input_width, 1197 sp_block_width); 1198 block_stripes[1].offset = 1199 rounddown(css_pipe->rect[IPU3_CSS_RECT_GDC].width - 1200 stripe_params[1].input_width, sp_block_width); 1201 block_stripes[1].width = 1202 roundup(css_pipe->rect[IPU3_CSS_RECT_GDC].width - 1203 block_stripes[1].offset, sp_block_width); 1204 block_stripes[0].height = css_pipe->rect[IPU3_CSS_RECT_GDC].height; 1205 block_stripes[1].height = block_stripes[0].height; 1206 } 1207 1208 return 0; 1209 } 1210 1211 /*********************** Mostly 3A operations ******************************/ 1212 1213 /* 1214 * This function creates a "TO-DO list" (operations) for the sp code. 1215 * 1216 * There are 2 types of operations: 1217 * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to 1218 * accelerator space (NOTE that this space is limited) associated data: 1219 * DDR address + accelerator's config set index(acc's address). 1220 * 1221 * 2. Issue "Process Lines Command" to shd accelerator 1222 * associated data: #lines + which config set to use (actually, accelerator 1223 * will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction 1224 * of not touching config sets x & (x+1)%num_of_sets when process_lines(x) 1225 * is active). 1226 * 1227 * Basically there are 2 types of operations "chunks": 1228 * 1. "initial chunk": Initially, we do as much transfers as we can (and need) 1229 * [0 - max sets(3) ] followed by 1 or 2 "process lines" operations. 1230 * 1231 * 2. "regular chunk" - 1 transfer followed by 1 process line operation. 1232 * (in some cases we might need additional transfer ate the last chunk). 1233 * 1234 * for some case: 1235 * --> init 1236 * tr (0) 1237 * tr (1) 1238 * tr (2) 1239 * pl (0) 1240 * pl (1) 1241 * --> ack (0) 1242 * tr (3) 1243 * pl (2) 1244 * --> ack (1) 1245 * pl (3) 1246 * --> ack (2) 1247 * do nothing 1248 * --> ack (3) 1249 * do nothing 1250 */ 1251 1252 static int 1253 imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops, 1254 const struct ipu3_uapi_shd_grid_config *grid, 1255 unsigned int image_height) 1256 { 1257 unsigned int block_height = 1 << grid->block_height_log2; 1258 unsigned int grid_height_per_slice = grid->grid_height_per_slice; 1259 unsigned int set_height = grid_height_per_slice * block_height; 1260 1261 /* We currently support only abs(y_start) > grid_height_per_slice */ 1262 unsigned int positive_y_start = (unsigned int)-grid->y_start; 1263 unsigned int first_process_lines = 1264 set_height - (positive_y_start % set_height); 1265 unsigned int last_set_height; 1266 unsigned int num_of_sets; 1267 1268 struct imgu_abi_acc_operation *p_op; 1269 struct imgu_abi_acc_process_lines_cmd_data *p_pl; 1270 struct imgu_abi_shd_transfer_luts_set_data *p_tr; 1271 1272 unsigned int op_idx, pl_idx, tr_idx; 1273 unsigned char tr_set_num, pl_cfg_set; 1274 1275 /* 1276 * When the number of lines for the last process lines command 1277 * is equal to a set height, we need another line of grid cell - 1278 * additional transfer is required. 1279 */ 1280 unsigned char last_tr = 0; 1281 1282 /* Add "process lines" command to the list of operations */ 1283 bool add_pl; 1284 /* Add DMA xfer (config set) command to the list of ops */ 1285 bool add_tr; 1286 1287 /* 1288 * Available partial grid (the part that fits into #IMGU_SHD_SETS sets) 1289 * doesn't cover whole frame - need to process in chunks 1290 */ 1291 if (image_height > first_process_lines) { 1292 last_set_height = 1293 (image_height - first_process_lines) % set_height; 1294 num_of_sets = last_set_height > 0 ? 1295 (image_height - first_process_lines) / set_height + 2 : 1296 (image_height - first_process_lines) / set_height + 1; 1297 last_tr = (set_height - last_set_height <= block_height || 1298 last_set_height == 0) ? 1 : 0; 1299 } else { /* partial grid covers whole frame */ 1300 last_set_height = 0; 1301 num_of_sets = 1; 1302 first_process_lines = image_height; 1303 last_tr = set_height - image_height <= block_height ? 1 : 0; 1304 } 1305 1306 /* Init operations lists and counters */ 1307 p_op = ops->operation_list; 1308 op_idx = 0; 1309 p_pl = ops->process_lines_data; 1310 pl_idx = 0; 1311 p_tr = ops->transfer_data; 1312 tr_idx = 0; 1313 1314 memset(ops, 0, sizeof(*ops)); 1315 1316 /* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */ 1317 tr_set_num = 0; 1318 pl_cfg_set = 0; 1319 1320 /* 1321 * Always start with a transfer - process lines command must be 1322 * initiated only after appropriate config sets are in place 1323 * (2 configuration sets per process line command, except for last one). 1324 */ 1325 add_pl = false; 1326 add_tr = true; 1327 1328 while (add_pl || add_tr) { 1329 /* Transfer ops */ 1330 if (add_tr) { 1331 if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS || 1332 tr_idx >= IMGU_ABI_SHD_MAX_TRANSFERS) 1333 return -EINVAL; 1334 p_op[op_idx].op_type = 1335 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA; 1336 p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE; 1337 op_idx++; 1338 p_tr[tr_idx].set_number = tr_set_num; 1339 tr_idx++; 1340 tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS; 1341 } 1342 1343 /* Process-lines ops */ 1344 if (add_pl) { 1345 if (op_idx >= IMGU_ABI_SHD_MAX_OPERATIONS || 1346 pl_idx >= IMGU_ABI_SHD_MAX_PROCESS_LINES) 1347 return -EINVAL; 1348 p_op[op_idx].op_type = 1349 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES; 1350 1351 /* 1352 * In case we have 2 process lines commands - 1353 * don't stop after the first one 1354 */ 1355 if (pl_idx == 0 && num_of_sets != 1) 1356 p_op[op_idx].op_indicator = 1357 IMGU_ABI_ACC_OP_IDLE; 1358 /* 1359 * Initiate last process lines command - 1360 * end of operation list. 1361 */ 1362 else if (pl_idx == num_of_sets - 1) 1363 p_op[op_idx].op_indicator = 1364 IMGU_ABI_ACC_OP_END_OF_OPS; 1365 /* 1366 * Intermediate process line command - end of operation 1367 * "chunk" (meaning few "transfers" followed by few 1368 * "process lines" commands). 1369 */ 1370 else 1371 p_op[op_idx].op_indicator = 1372 IMGU_ABI_ACC_OP_END_OF_ACK; 1373 1374 op_idx++; 1375 1376 /* first process line operation */ 1377 if (pl_idx == 0) 1378 p_pl[pl_idx].lines = first_process_lines; 1379 /* Last process line operation */ 1380 else if (pl_idx == num_of_sets - 1 && 1381 last_set_height > 0) 1382 p_pl[pl_idx].lines = last_set_height; 1383 else /* "regular" process lines operation */ 1384 p_pl[pl_idx].lines = set_height; 1385 1386 p_pl[pl_idx].cfg_set = pl_cfg_set; 1387 pl_idx++; 1388 pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS; 1389 } 1390 1391 /* 1392 * Initially, we always transfer 1393 * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the 1394 * corresponding process lines commands. 1395 */ 1396 if (tr_idx == IMGU_SHD_SETS || 1397 tr_idx == num_of_sets + last_tr) { 1398 add_tr = false; 1399 add_pl = true; 1400 } 1401 1402 /* 1403 * We have finished the "initial" operations chunk - 1404 * be ready to get more chunks. 1405 */ 1406 if (pl_idx == 2) { 1407 add_tr = true; 1408 add_pl = true; 1409 } 1410 1411 /* Stop conditions for each operation type */ 1412 if (tr_idx == num_of_sets + last_tr) 1413 add_tr = false; 1414 if (pl_idx == num_of_sets) 1415 add_pl = false; 1416 } 1417 1418 return 0; 1419 } 1420 1421 /* 1422 * The follow handshake procotol is the same for AF, AWB and AWB FR. 1423 * 1424 * for n sets of meta-data, the flow is: 1425 * --> init 1426 * process-lines (0) 1427 * process-lines (1) eoc 1428 * --> ack (0) 1429 * read-meta-data (0) 1430 * process-lines (2) eoc 1431 * --> ack (1) 1432 * read-meta-data (1) 1433 * process-lines (3) eoc 1434 * ... 1435 * 1436 * --> ack (n-3) 1437 * read-meta-data (n-3) 1438 * process-lines (n-1) eoc 1439 * --> ack (n-2) 1440 * read-meta-data (n-2) eoc 1441 * --> ack (n-1) 1442 * read-meta-data (n-1) eof 1443 * 1444 * for 2 sets we get: 1445 * --> init 1446 * pl (0) 1447 * pl (1) eoc 1448 * --> ack (0) 1449 * pl (2) - rest of image, if applicable) 1450 * rmd (0) eoc 1451 * --> ack (1) 1452 * rmd (1) eof 1453 * --> (ack (2)) 1454 * do nothing 1455 * 1456 * for only one set: 1457 * 1458 * --> init 1459 * pl(0) eoc 1460 * --> ack (0) 1461 * rmd (0) eof 1462 * 1463 * grid smaller than image case 1464 * for example 128x128 grid (block size 8x8, 16x16 num of blocks) 1465 * start at (0,0) 1466 * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal 1467 * => 1st process lines = 80 1468 * we're left with 128-80=48 lines (6 blocks vertical) 1469 * => 2nd process lines = 48 1470 * last process lines to cover the image - image_height - 128 1471 * 1472 * --> init 1473 * pl (0) first 1474 * pl (1) last-in-grid 1475 * --> ack (0) 1476 * rmd (0) 1477 * pl (2) after-grid 1478 * --> ack (1) 1479 * rmd (1) eof 1480 * --> ack (2) 1481 * do nothing 1482 */ 1483 struct process_lines { 1484 unsigned int image_height; 1485 unsigned short grid_height; 1486 unsigned short block_height; 1487 unsigned short y_start; 1488 unsigned char grid_height_per_slice; 1489 1490 unsigned short max_op; /* max operation */ 1491 unsigned short max_tr; /* max transaction */ 1492 unsigned char acc_enable; 1493 }; 1494 1495 /* Helper to config intra_frame_operations_data. */ 1496 static int 1497 imgu_css_acc_process_lines(const struct process_lines *pl, 1498 struct imgu_abi_acc_operation *p_op, 1499 struct imgu_abi_acc_process_lines_cmd_data *p_pl, 1500 struct imgu_abi_acc_transfer_op_data *p_tr) 1501 { 1502 unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0; 1503 unsigned char tr_set_num = 0, pl_cfg_set = 0; 1504 const unsigned short grid_last_line = 1505 pl->y_start + pl->grid_height * pl->block_height; 1506 const unsigned short process_lines = 1507 pl->grid_height_per_slice * pl->block_height; 1508 1509 unsigned int process_lines_after_grid; 1510 unsigned short first_process_lines; 1511 unsigned short last_process_lines_in_grid; 1512 1513 unsigned short num_of_process_lines; 1514 unsigned short num_of_sets; 1515 1516 if (pl->grid_height_per_slice == 0) 1517 return -EINVAL; 1518 1519 if (pl->acc_enable && grid_last_line > pl->image_height) 1520 return -EINVAL; 1521 1522 num_of_sets = pl->grid_height / pl->grid_height_per_slice; 1523 if (num_of_sets * pl->grid_height_per_slice < pl->grid_height) 1524 num_of_sets++; 1525 1526 /* Account for two line delay inside the FF */ 1527 if (pl->max_op == IMGU_ABI_AF_MAX_OPERATIONS) { 1528 first_process_lines = process_lines + pl->y_start + 2; 1529 last_process_lines_in_grid = 1530 (grid_last_line - first_process_lines) - 1531 ((num_of_sets - 2) * process_lines) + 4; 1532 process_lines_after_grid = 1533 pl->image_height - grid_last_line - 4; 1534 } else { 1535 first_process_lines = process_lines + pl->y_start; 1536 last_process_lines_in_grid = 1537 (grid_last_line - first_process_lines) - 1538 ((num_of_sets - 2) * process_lines); 1539 process_lines_after_grid = pl->image_height - grid_last_line; 1540 } 1541 1542 num_of_process_lines = num_of_sets; 1543 if (process_lines_after_grid > 0) 1544 num_of_process_lines++; 1545 1546 while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) { 1547 /* Read meta-data */ 1548 if (pl_idx >= 2 || (pl_idx == 1 && num_of_sets == 1)) { 1549 if (op_idx >= pl->max_op || tr_idx >= pl->max_tr) 1550 return -EINVAL; 1551 1552 p_op[op_idx].op_type = 1553 IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA; 1554 1555 if (tr_idx == num_of_sets - 1) 1556 /* The last operation is always a tr */ 1557 p_op[op_idx].op_indicator = 1558 IMGU_ABI_ACC_OP_END_OF_OPS; 1559 else if (tr_idx == num_of_sets - 2) 1560 if (process_lines_after_grid == 0) 1561 /* 1562 * No additional pl op left - 1563 * this op is left as lats of cycle 1564 */ 1565 p_op[op_idx].op_indicator = 1566 IMGU_ABI_ACC_OP_END_OF_ACK; 1567 else 1568 /* 1569 * We still have to process-lines after 1570 * the grid so have one more pl op 1571 */ 1572 p_op[op_idx].op_indicator = 1573 IMGU_ABI_ACC_OP_IDLE; 1574 else 1575 /* Default - usually there's a pl after a tr */ 1576 p_op[op_idx].op_indicator = 1577 IMGU_ABI_ACC_OP_IDLE; 1578 1579 op_idx++; 1580 if (p_tr) { 1581 p_tr[tr_idx].set_number = tr_set_num; 1582 tr_set_num = 1 - tr_set_num; 1583 } 1584 tr_idx++; 1585 } 1586 1587 /* process_lines */ 1588 if (pl_idx < num_of_process_lines) { 1589 if (op_idx >= pl->max_op || pl_idx >= pl->max_tr) 1590 return -EINVAL; 1591 1592 p_op[op_idx].op_type = 1593 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES; 1594 if (pl_idx == 0) 1595 if (num_of_process_lines == 1) 1596 /* Only one pl op */ 1597 p_op[op_idx].op_indicator = 1598 IMGU_ABI_ACC_OP_END_OF_ACK; 1599 else 1600 /* On init - do two pl ops */ 1601 p_op[op_idx].op_indicator = 1602 IMGU_ABI_ACC_OP_IDLE; 1603 else 1604 /* Usually pl is the end of the ack cycle */ 1605 p_op[op_idx].op_indicator = 1606 IMGU_ABI_ACC_OP_END_OF_ACK; 1607 1608 op_idx++; 1609 1610 if (pl_idx == 0) 1611 /* First process line */ 1612 p_pl[pl_idx].lines = first_process_lines; 1613 else if (pl_idx == num_of_sets - 1) 1614 /* Last in grid */ 1615 p_pl[pl_idx].lines = last_process_lines_in_grid; 1616 else if (pl_idx == num_of_process_lines - 1) 1617 /* After the grid */ 1618 p_pl[pl_idx].lines = process_lines_after_grid; 1619 else 1620 /* Inside the grid */ 1621 p_pl[pl_idx].lines = process_lines; 1622 1623 if (p_tr) { 1624 p_pl[pl_idx].cfg_set = pl_cfg_set; 1625 pl_cfg_set = 1 - pl_cfg_set; 1626 } 1627 pl_idx++; 1628 } 1629 } 1630 1631 return 0; 1632 } 1633 1634 static int imgu_css_af_ops_calc(struct imgu_css *css, unsigned int pipe, 1635 struct imgu_abi_af_config *af_config) 1636 { 1637 struct imgu_abi_af_intra_frame_operations_data *to = 1638 &af_config->operations_data; 1639 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1640 struct imgu_fw_info *bi = 1641 &css->fwp->binary_header[css_pipe->bindex]; 1642 1643 struct process_lines pl = { 1644 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height, 1645 .grid_height = af_config->config.grid_cfg.height, 1646 .block_height = 1647 1 << af_config->config.grid_cfg.block_height_log2, 1648 .y_start = af_config->config.grid_cfg.y_start & 1649 IPU3_UAPI_GRID_START_MASK, 1650 .grid_height_per_slice = 1651 af_config->stripes[0].grid_cfg.height_per_slice, 1652 .max_op = IMGU_ABI_AF_MAX_OPERATIONS, 1653 .max_tr = IMGU_ABI_AF_MAX_TRANSFERS, 1654 .acc_enable = bi->info.isp.sp.enable.af, 1655 }; 1656 1657 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data, 1658 NULL); 1659 } 1660 1661 static int 1662 imgu_css_awb_fr_ops_calc(struct imgu_css *css, unsigned int pipe, 1663 struct imgu_abi_awb_fr_config *awb_fr_config) 1664 { 1665 struct imgu_abi_awb_fr_intra_frame_operations_data *to = 1666 &awb_fr_config->operations_data; 1667 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1668 struct imgu_fw_info *bi = 1669 &css->fwp->binary_header[css_pipe->bindex]; 1670 struct process_lines pl = { 1671 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height, 1672 .grid_height = awb_fr_config->config.grid_cfg.height, 1673 .block_height = 1674 1 << awb_fr_config->config.grid_cfg.block_height_log2, 1675 .y_start = awb_fr_config->config.grid_cfg.y_start & 1676 IPU3_UAPI_GRID_START_MASK, 1677 .grid_height_per_slice = 1678 awb_fr_config->stripes[0].grid_cfg.height_per_slice, 1679 .max_op = IMGU_ABI_AWB_FR_MAX_OPERATIONS, 1680 .max_tr = IMGU_ABI_AWB_FR_MAX_PROCESS_LINES, 1681 .acc_enable = bi->info.isp.sp.enable.awb_fr_acc, 1682 }; 1683 1684 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data, 1685 NULL); 1686 } 1687 1688 static int imgu_css_awb_ops_calc(struct imgu_css *css, unsigned int pipe, 1689 struct imgu_abi_awb_config *awb_config) 1690 { 1691 struct imgu_abi_awb_intra_frame_operations_data *to = 1692 &awb_config->operations_data; 1693 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1694 struct imgu_fw_info *bi = 1695 &css->fwp->binary_header[css_pipe->bindex]; 1696 1697 struct process_lines pl = { 1698 .image_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height, 1699 .grid_height = awb_config->config.grid.height, 1700 .block_height = 1701 1 << awb_config->config.grid.block_height_log2, 1702 .y_start = awb_config->config.grid.y_start, 1703 .grid_height_per_slice = 1704 awb_config->stripes[0].grid.height_per_slice, 1705 .max_op = IMGU_ABI_AWB_MAX_OPERATIONS, 1706 .max_tr = IMGU_ABI_AWB_MAX_TRANSFERS, 1707 .acc_enable = bi->info.isp.sp.enable.awb_acc, 1708 }; 1709 1710 return imgu_css_acc_process_lines(&pl, to->ops, to->process_lines_data, 1711 to->transfer_data); 1712 } 1713 1714 static u16 imgu_css_grid_end(u16 start, u8 width, u8 block_width_log2) 1715 { 1716 return (start & IPU3_UAPI_GRID_START_MASK) + 1717 (width << block_width_log2) - 1; 1718 } 1719 1720 static void imgu_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg) 1721 { 1722 grid_cfg->x_end = imgu_css_grid_end(grid_cfg->x_start, grid_cfg->width, 1723 grid_cfg->block_width_log2); 1724 grid_cfg->y_end = imgu_css_grid_end(grid_cfg->y_start, grid_cfg->height, 1725 grid_cfg->block_height_log2); 1726 } 1727 1728 /****************** config computation *****************************/ 1729 1730 static int imgu_css_cfg_acc_stripe(struct imgu_css *css, unsigned int pipe, 1731 struct imgu_abi_acc_param *acc) 1732 { 1733 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1734 const struct imgu_fw_info *bi = 1735 &css->fwp->binary_header[css_pipe->bindex]; 1736 struct imgu_css_scaler_info scaler_luma, scaler_chroma; 1737 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes; 1738 const unsigned int f = IPU3_UAPI_ISP_VEC_ELEMS * 2; 1739 unsigned int bds_ds, i; 1740 1741 memset(acc, 0, sizeof(*acc)); 1742 1743 /* acc_param: osys_config */ 1744 1745 if (imgu_css_osys_calc(css, pipe, stripes, &acc->osys, &scaler_luma, 1746 &scaler_chroma, acc->stripe.block_stripes)) 1747 return -EINVAL; 1748 1749 /* acc_param: stripe data */ 1750 1751 /* 1752 * For the striped case the approach is as follows: 1753 * 1. down-scaled stripes are calculated - with 128 overlap 1754 * (this is the main limiter therefore it's first) 1755 * 2. input stripes are derived by up-scaling the down-scaled stripes 1756 * (there are no alignment requirements on input stripes) 1757 * 3. output stripes are derived from down-scaled stripes too 1758 */ 1759 1760 acc->stripe.num_of_stripes = stripes; 1761 acc->stripe.input_frame.width = 1762 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width; 1763 acc->stripe.input_frame.height = 1764 css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height; 1765 acc->stripe.input_frame.bayer_order = 1766 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order; 1767 1768 for (i = 0; i < stripes; i++) 1769 acc->stripe.bds_out_stripes[i].height = 1770 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1771 acc->stripe.bds_out_stripes[0].offset = 0; 1772 if (stripes <= 1) { 1773 acc->stripe.bds_out_stripes[0].width = 1774 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f); 1775 } else { 1776 /* Image processing is divided into two stripes */ 1777 acc->stripe.bds_out_stripes[0].width = 1778 acc->stripe.bds_out_stripes[1].width = 1779 (css_pipe->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f; 1780 /* 1781 * Sum of width of the two stripes should not be smaller 1782 * than output width and must be even times of overlapping 1783 * unit f. 1784 */ 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 if ((css_pipe->rect[IPU3_CSS_RECT_BDS].width / f & 1) && 1789 (css_pipe->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) { 1790 acc->stripe.bds_out_stripes[0].width += f; 1791 acc->stripe.bds_out_stripes[1].width += f; 1792 } 1793 /* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */ 1794 acc->stripe.bds_out_stripes[1].offset = 1795 acc->stripe.bds_out_stripes[0].width - 2 * f; 1796 } 1797 1798 acc->stripe.effective_stripes[0].height = 1799 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height; 1800 acc->stripe.effective_stripes[0].offset = 0; 1801 acc->stripe.bds_out_stripes_no_overlap[0].height = 1802 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1803 acc->stripe.bds_out_stripes_no_overlap[0].offset = 0; 1804 acc->stripe.output_stripes[0].height = 1805 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 1806 acc->stripe.output_stripes[0].offset = 0; 1807 if (stripes <= 1) { 1808 acc->stripe.down_scaled_stripes[0].width = 1809 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 1810 acc->stripe.down_scaled_stripes[0].height = 1811 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1812 acc->stripe.down_scaled_stripes[0].offset = 0; 1813 1814 acc->stripe.effective_stripes[0].width = 1815 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width; 1816 acc->stripe.bds_out_stripes_no_overlap[0].width = 1817 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f); 1818 1819 acc->stripe.output_stripes[0].width = 1820 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width; 1821 } else { /* Two stripes */ 1822 bds_ds = css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width * 1823 IMGU_BDS_GRANULARITY / 1824 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 1825 1826 acc->stripe.down_scaled_stripes[0] = 1827 acc->stripe.bds_out_stripes[0]; 1828 acc->stripe.down_scaled_stripes[1] = 1829 acc->stripe.bds_out_stripes[1]; 1830 if (!IS_ALIGNED(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f)) 1831 acc->stripe.down_scaled_stripes[1].width += 1832 (css_pipe->rect[IPU3_CSS_RECT_BDS].width 1833 & (f - 1)) - f; 1834 1835 acc->stripe.effective_stripes[0].width = bds_ds * 1836 acc->stripe.down_scaled_stripes[0].width / 1837 IMGU_BDS_GRANULARITY; 1838 acc->stripe.effective_stripes[1].width = bds_ds * 1839 acc->stripe.down_scaled_stripes[1].width / 1840 IMGU_BDS_GRANULARITY; 1841 acc->stripe.effective_stripes[1].height = 1842 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height; 1843 acc->stripe.effective_stripes[1].offset = bds_ds * 1844 acc->stripe.down_scaled_stripes[1].offset / 1845 IMGU_BDS_GRANULARITY; 1846 1847 acc->stripe.bds_out_stripes_no_overlap[0].width = 1848 acc->stripe.bds_out_stripes_no_overlap[1].offset = 1849 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2; 1850 acc->stripe.bds_out_stripes_no_overlap[1].width = 1851 DIV_ROUND_UP(css_pipe->rect[IPU3_CSS_RECT_BDS].width, f) 1852 / 2 * f; 1853 acc->stripe.bds_out_stripes_no_overlap[1].height = 1854 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1855 1856 acc->stripe.output_stripes[0].width = 1857 acc->stripe.down_scaled_stripes[0].width - f; 1858 acc->stripe.output_stripes[1].width = 1859 acc->stripe.down_scaled_stripes[1].width - f; 1860 acc->stripe.output_stripes[1].height = 1861 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 1862 acc->stripe.output_stripes[1].offset = 1863 acc->stripe.output_stripes[0].width; 1864 } 1865 1866 acc->stripe.output_system_in_frame_width = 1867 css_pipe->rect[IPU3_CSS_RECT_GDC].width; 1868 acc->stripe.output_system_in_frame_height = 1869 css_pipe->rect[IPU3_CSS_RECT_GDC].height; 1870 1871 acc->stripe.effective_frame_width = 1872 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width; 1873 acc->stripe.bds_frame_width = css_pipe->rect[IPU3_CSS_RECT_BDS].width; 1874 acc->stripe.out_frame_width = 1875 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width; 1876 acc->stripe.out_frame_height = 1877 css_pipe->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height; 1878 acc->stripe.gdc_in_buffer_width = 1879 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline / 1880 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel; 1881 acc->stripe.gdc_in_buffer_height = 1882 css_pipe->aux_frames[IPU3_CSS_AUX_FRAME_REF].height; 1883 acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X; 1884 acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y; 1885 acc->stripe.display_frame_width = 1886 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width; 1887 acc->stripe.display_frame_height = 1888 css_pipe->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height; 1889 acc->stripe.bds_aligned_frame_width = 1890 roundup(css_pipe->rect[IPU3_CSS_RECT_BDS].width, 1891 2 * IPU3_UAPI_ISP_VEC_ELEMS); 1892 1893 if (stripes > 1) 1894 acc->stripe.half_overlap_vectors = 1895 IMGU_STRIPE_FIXED_HALF_OVERLAP; 1896 else 1897 acc->stripe.half_overlap_vectors = 0; 1898 1899 return 0; 1900 } 1901 1902 static void imgu_css_cfg_acc_dvs(struct imgu_css *css, 1903 struct imgu_abi_acc_param *acc, 1904 unsigned int pipe) 1905 { 1906 unsigned int i; 1907 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1908 1909 /* Disable DVS statistics */ 1910 acc->dvs_stat.operations_data.process_lines_data[0].lines = 1911 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1912 acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0; 1913 acc->dvs_stat.operations_data.ops[0].op_type = 1914 IMGU_ABI_ACC_OPTYPE_PROCESS_LINES; 1915 acc->dvs_stat.operations_data.ops[0].op_indicator = 1916 IMGU_ABI_ACC_OP_NO_OPS; 1917 for (i = 0; i < IMGU_ABI_DVS_STAT_LEVELS; i++) 1918 acc->dvs_stat.cfg.grd_config[i].enable = 0; 1919 } 1920 1921 static void acc_bds_per_stripe_data(struct imgu_css *css, 1922 struct imgu_abi_acc_param *acc, 1923 const int i, unsigned int pipe) 1924 { 1925 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1926 1927 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0; 1928 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0; 1929 acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0; 1930 acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 = 1931 acc->bds.hor.hor_ctrl0; 1932 acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width = 1933 acc->stripe.down_scaled_stripes[i].width; 1934 acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width = 1935 acc->stripe.down_scaled_stripes[i].width; 1936 acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height = 1937 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 1938 } 1939 1940 /* 1941 * Configure `acc' parameters. `acc_old' contains the old values (or is NULL) 1942 * and `acc_user' contains new prospective values. `use' contains flags 1943 * telling which fields to take from the old values (or generate if it is NULL) 1944 * and which to take from the new user values. 1945 */ 1946 int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, 1947 struct ipu3_uapi_flags *use, 1948 struct imgu_abi_acc_param *acc, 1949 struct imgu_abi_acc_param *acc_old, 1950 struct ipu3_uapi_acc_param *acc_user) 1951 { 1952 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 1953 const struct imgu_fw_info *bi = 1954 &css->fwp->binary_header[css_pipe->bindex]; 1955 const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes; 1956 const unsigned int tnr_frame_width = 1957 acc->stripe.bds_aligned_frame_width; 1958 const unsigned int min_overlap = 10; 1959 const struct v4l2_pix_format_mplane *pixm = 1960 &css_pipe->queue[IPU3_CSS_QUEUE_IN].fmt.mpix; 1961 const struct imgu_css_bds_config *cfg_bds; 1962 struct imgu_abi_input_feeder_data *feeder_data; 1963 1964 unsigned int bds_ds, ofs_x, ofs_y, i, width, height; 1965 u8 b_w_log2; /* Block width log2 */ 1966 1967 /* Update stripe using chroma and luma */ 1968 1969 if (imgu_css_cfg_acc_stripe(css, pipe, acc)) 1970 return -EINVAL; 1971 1972 /* acc_param: input_feeder_config */ 1973 1974 ofs_x = ((pixm->width - 1975 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1; 1976 ofs_x += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1977 IMGU_ABI_BAYER_ORDER_RGGB || 1978 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1979 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0; 1980 ofs_y = ((pixm->height - 1981 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1; 1982 ofs_y += css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1983 IMGU_ABI_BAYER_ORDER_BGGR || 1984 css_pipe->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order == 1985 IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0; 1986 acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline; 1987 acc->input_feeder.data.start_row_address = 1988 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD + 1989 ofs_y * acc->input_feeder.data.row_stride; 1990 acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD; 1991 1992 acc->input_feeder.data_per_stripe.input_feeder_data[0].data = 1993 acc->input_feeder.data; 1994 1995 ofs_x += acc->stripe.effective_stripes[1].offset; 1996 1997 feeder_data = 1998 &acc->input_feeder.data_per_stripe.input_feeder_data[1].data; 1999 feeder_data->row_stride = acc->input_feeder.data.row_stride; 2000 feeder_data->start_row_address = 2001 ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD + 2002 ofs_y * acc->input_feeder.data.row_stride; 2003 feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD; 2004 2005 /* acc_param: bnr_static_config */ 2006 2007 /* 2008 * Originate from user or be the original default values if user has 2009 * never set them before, when user gives a new set of parameters, 2010 * for each chunk in the parameter structure there is a flag use->xxx 2011 * whether to use the user-provided parameter or not. If not, the 2012 * parameter remains unchanged in the driver: 2013 * it's value is taken from acc_old. 2014 */ 2015 if (use && use->acc_bnr) { 2016 /* Take values from user */ 2017 acc->bnr = acc_user->bnr; 2018 } else if (acc_old) { 2019 /* Use old value */ 2020 acc->bnr = acc_old->bnr; 2021 } else { 2022 /* Calculate from scratch */ 2023 acc->bnr = imgu_css_bnr_defaults; 2024 } 2025 2026 acc->bnr.column_size = tnr_frame_width; 2027 2028 /* acc_param: bnr_static_config_green_disparity */ 2029 2030 if (use && use->acc_green_disparity) { 2031 /* Take values from user */ 2032 acc->green_disparity = acc_user->green_disparity; 2033 } else if (acc_old) { 2034 /* Use old value */ 2035 acc->green_disparity = acc_old->green_disparity; 2036 } else { 2037 /* Calculate from scratch */ 2038 memset(&acc->green_disparity, 0, sizeof(acc->green_disparity)); 2039 } 2040 2041 /* acc_param: dm_config */ 2042 2043 if (use && use->acc_dm) { 2044 /* Take values from user */ 2045 acc->dm = acc_user->dm; 2046 } else if (acc_old) { 2047 /* Use old value */ 2048 acc->dm = acc_old->dm; 2049 } else { 2050 /* Calculate from scratch */ 2051 acc->dm = imgu_css_dm_defaults; 2052 } 2053 2054 acc->dm.frame_width = tnr_frame_width; 2055 2056 /* acc_param: ccm_mat_config */ 2057 2058 if (use && use->acc_ccm) { 2059 /* Take values from user */ 2060 acc->ccm = acc_user->ccm; 2061 } else if (acc_old) { 2062 /* Use old value */ 2063 acc->ccm = acc_old->ccm; 2064 } else { 2065 /* Calculate from scratch */ 2066 acc->ccm = imgu_css_ccm_defaults; 2067 } 2068 2069 /* acc_param: gamma_config */ 2070 2071 if (use && use->acc_gamma) { 2072 /* Take values from user */ 2073 acc->gamma = acc_user->gamma; 2074 } else if (acc_old) { 2075 /* Use old value */ 2076 acc->gamma = acc_old->gamma; 2077 } else { 2078 /* Calculate from scratch */ 2079 acc->gamma.gc_ctrl.enable = 1; 2080 acc->gamma.gc_lut = imgu_css_gamma_lut; 2081 } 2082 2083 /* acc_param: csc_mat_config */ 2084 2085 if (use && use->acc_csc) { 2086 /* Take values from user */ 2087 acc->csc = acc_user->csc; 2088 } else if (acc_old) { 2089 /* Use old value */ 2090 acc->csc = acc_old->csc; 2091 } else { 2092 /* Calculate from scratch */ 2093 acc->csc = imgu_css_csc_defaults; 2094 } 2095 2096 /* acc_param: cds_params */ 2097 2098 if (use && use->acc_cds) { 2099 /* Take values from user */ 2100 acc->cds = acc_user->cds; 2101 } else if (acc_old) { 2102 /* Use old value */ 2103 acc->cds = acc_old->cds; 2104 } else { 2105 /* Calculate from scratch */ 2106 acc->cds = imgu_css_cds_defaults; 2107 } 2108 2109 /* acc_param: shd_config */ 2110 2111 if (use && use->acc_shd) { 2112 /* Take values from user */ 2113 acc->shd.shd = acc_user->shd.shd; 2114 acc->shd.shd_lut = acc_user->shd.shd_lut; 2115 } else if (acc_old) { 2116 /* Use old value */ 2117 acc->shd.shd = acc_old->shd.shd; 2118 acc->shd.shd_lut = acc_old->shd.shd_lut; 2119 } else { 2120 /* Calculate from scratch */ 2121 acc->shd.shd = imgu_css_shd_defaults; 2122 memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut)); 2123 } 2124 2125 if (acc->shd.shd.grid.width <= 0) 2126 return -EINVAL; 2127 2128 acc->shd.shd.grid.grid_height_per_slice = 2129 IMGU_ABI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width; 2130 2131 if (acc->shd.shd.grid.grid_height_per_slice <= 0) 2132 return -EINVAL; 2133 2134 acc->shd.shd.general.init_set_vrt_offst_ul = 2135 (-acc->shd.shd.grid.y_start >> 2136 acc->shd.shd.grid.block_height_log2) % 2137 acc->shd.shd.grid.grid_height_per_slice; 2138 2139 if (imgu_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid, 2140 css_pipe->rect[IPU3_CSS_RECT_BDS].height)) 2141 return -EINVAL; 2142 2143 /* acc_param: dvs_stat_config */ 2144 imgu_css_cfg_acc_dvs(css, acc, pipe); 2145 2146 /* acc_param: yuvp1_iefd_config */ 2147 2148 if (use && use->acc_iefd) { 2149 /* Take values from user */ 2150 acc->iefd = acc_user->iefd; 2151 } else if (acc_old) { 2152 /* Use old value */ 2153 acc->iefd = acc_old->iefd; 2154 } else { 2155 /* Calculate from scratch */ 2156 acc->iefd = imgu_css_iefd_defaults; 2157 } 2158 2159 /* acc_param: yuvp1_yds_config yds_c0 */ 2160 2161 if (use && use->acc_yds_c0) { 2162 /* Take values from user */ 2163 acc->yds_c0 = acc_user->yds_c0; 2164 } else if (acc_old) { 2165 /* Use old value */ 2166 acc->yds_c0 = acc_old->yds_c0; 2167 } else { 2168 /* Calculate from scratch */ 2169 acc->yds_c0 = imgu_css_yds_defaults; 2170 } 2171 2172 /* acc_param: yuvp1_chnr_config chnr_c0 */ 2173 2174 if (use && use->acc_chnr_c0) { 2175 /* Take values from user */ 2176 acc->chnr_c0 = acc_user->chnr_c0; 2177 } else if (acc_old) { 2178 /* Use old value */ 2179 acc->chnr_c0 = acc_old->chnr_c0; 2180 } else { 2181 /* Calculate from scratch */ 2182 acc->chnr_c0 = imgu_css_chnr_defaults; 2183 } 2184 2185 /* acc_param: yuvp1_y_ee_nr_config */ 2186 2187 if (use && use->acc_y_ee_nr) { 2188 /* Take values from user */ 2189 acc->y_ee_nr = acc_user->y_ee_nr; 2190 } else if (acc_old) { 2191 /* Use old value */ 2192 acc->y_ee_nr = acc_old->y_ee_nr; 2193 } else { 2194 /* Calculate from scratch */ 2195 acc->y_ee_nr = imgu_css_y_ee_nr_defaults; 2196 } 2197 2198 /* acc_param: yuvp1_yds_config yds */ 2199 2200 if (use && use->acc_yds) { 2201 /* Take values from user */ 2202 acc->yds = acc_user->yds; 2203 } else if (acc_old) { 2204 /* Use old value */ 2205 acc->yds = acc_old->yds; 2206 } else { 2207 /* Calculate from scratch */ 2208 acc->yds = imgu_css_yds_defaults; 2209 } 2210 2211 /* acc_param: yuvp1_chnr_config chnr */ 2212 2213 if (use && use->acc_chnr) { 2214 /* Take values from user */ 2215 acc->chnr = acc_user->chnr; 2216 } else if (acc_old) { 2217 /* Use old value */ 2218 acc->chnr = acc_old->chnr; 2219 } else { 2220 /* Calculate from scratch */ 2221 acc->chnr = imgu_css_chnr_defaults; 2222 } 2223 2224 /* acc_param: yuvp2_y_tm_lut_static_config */ 2225 2226 for (i = 0; i < IMGU_ABI_YUVP2_YTM_LUT_ENTRIES; i++) 2227 acc->ytm.entries[i] = i * 32; 2228 acc->ytm.enable = 0; /* Always disabled on IPU3 */ 2229 2230 /* acc_param: yuvp1_yds_config yds2 */ 2231 2232 if (use && use->acc_yds2) { 2233 /* Take values from user */ 2234 acc->yds2 = acc_user->yds2; 2235 } else if (acc_old) { 2236 /* Use old value */ 2237 acc->yds2 = acc_old->yds2; 2238 } else { 2239 /* Calculate from scratch */ 2240 acc->yds2 = imgu_css_yds_defaults; 2241 } 2242 2243 /* acc_param: yuvp2_tcc_static_config */ 2244 2245 if (use && use->acc_tcc) { 2246 /* Take values from user */ 2247 acc->tcc = acc_user->tcc; 2248 } else if (acc_old) { 2249 /* Use old value */ 2250 acc->tcc = acc_old->tcc; 2251 } else { 2252 /* Calculate from scratch */ 2253 memset(&acc->tcc, 0, sizeof(acc->tcc)); 2254 2255 acc->tcc.gen_control.en = 1; 2256 acc->tcc.gen_control.blend_shift = 3; 2257 acc->tcc.gen_control.gain_according_to_y_only = 1; 2258 acc->tcc.gen_control.gamma = 8; 2259 acc->tcc.gen_control.delta = 0; 2260 2261 for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) { 2262 acc->tcc.macc_table.entries[i].a = 1024; 2263 acc->tcc.macc_table.entries[i].b = 0; 2264 acc->tcc.macc_table.entries[i].c = 0; 2265 acc->tcc.macc_table.entries[i].d = 1024; 2266 } 2267 2268 acc->tcc.inv_y_lut.entries[6] = 1023; 2269 for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++) 2270 acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6); 2271 2272 acc->tcc.gain_pcwl = imgu_css_tcc_gain_pcwl_lut; 2273 acc->tcc.r_sqr_lut = imgu_css_tcc_r_sqr_lut; 2274 } 2275 2276 /* acc_param: dpc_config */ 2277 2278 if (use && use->acc_dpc) 2279 return -EINVAL; /* Not supported yet */ 2280 2281 /* Just disable by default */ 2282 memset(&acc->dpc, 0, sizeof(acc->dpc)); 2283 2284 /* acc_param: bds_config */ 2285 2286 bds_ds = (css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height * 2287 IMGU_BDS_GRANULARITY) / css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2288 if (bds_ds < IMGU_BDS_MIN_SF_INV || 2289 bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(imgu_css_bds_configs)) 2290 return -EINVAL; 2291 2292 cfg_bds = &imgu_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV]; 2293 acc->bds.hor.hor_ctrl1.hor_crop_en = 0; 2294 acc->bds.hor.hor_ctrl1.hor_crop_start = 0; 2295 acc->bds.hor.hor_ctrl1.hor_crop_end = 0; 2296 acc->bds.hor.hor_ctrl0.sample_patrn_length = 2297 cfg_bds->sample_patrn_length; 2298 acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en; 2299 acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL; 2300 acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL; 2301 acc->bds.hor.hor_ctrl0.out_frame_width = 2302 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 2303 acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr; 2304 acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr; 2305 acc->bds.hor.hor_ctrl2.input_frame_height = 2306 css_pipe->rect[IPU3_CSS_RECT_EFFECTIVE].height; 2307 acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL; 2308 acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL; 2309 acc->bds.ver.ver_ctrl0.sample_patrn_length = 2310 cfg_bds->sample_patrn_length; 2311 acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en; 2312 acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr; 2313 acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr; 2314 acc->bds.ver.ver_ctrl1.out_frame_width = 2315 css_pipe->rect[IPU3_CSS_RECT_BDS].width; 2316 acc->bds.ver.ver_ctrl1.out_frame_height = 2317 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2318 for (i = 0; i < stripes; i++) 2319 acc_bds_per_stripe_data(css, acc, i, pipe); 2320 2321 acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en; 2322 2323 /* acc_param: anr_config */ 2324 2325 if (use && use->acc_anr) { 2326 /* Take values from user */ 2327 acc->anr.transform = acc_user->anr.transform; 2328 acc->anr.stitch.anr_stitch_en = 2329 acc_user->anr.stitch.anr_stitch_en; 2330 memcpy(acc->anr.stitch.pyramid, acc_user->anr.stitch.pyramid, 2331 sizeof(acc->anr.stitch.pyramid)); 2332 } else if (acc_old) { 2333 /* Use old value */ 2334 acc->anr.transform = acc_old->anr.transform; 2335 acc->anr.stitch.anr_stitch_en = 2336 acc_old->anr.stitch.anr_stitch_en; 2337 memcpy(acc->anr.stitch.pyramid, acc_old->anr.stitch.pyramid, 2338 sizeof(acc->anr.stitch.pyramid)); 2339 } else { 2340 /* Calculate from scratch */ 2341 acc->anr = imgu_css_anr_defaults; 2342 } 2343 2344 /* Always enabled */ 2345 acc->anr.search.enable = 1; 2346 acc->anr.transform.enable = 1; 2347 acc->anr.tile2strm.enable = 1; 2348 acc->anr.tile2strm.frame_width = 2349 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN); 2350 acc->anr.search.frame_width = acc->anr.tile2strm.frame_width; 2351 acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width; 2352 acc->anr.tile2strm.frame_height = css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2353 acc->anr.search.frame_height = acc->anr.tile2strm.frame_height; 2354 acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height; 2355 2356 width = ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN); 2357 height = css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2358 2359 if (acc->anr.transform.xreset + width > IPU3_UAPI_ANR_MAX_RESET) 2360 acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_RESET - width; 2361 if (acc->anr.transform.xreset < IPU3_UAPI_ANR_MIN_RESET) 2362 acc->anr.transform.xreset = IPU3_UAPI_ANR_MIN_RESET; 2363 2364 if (acc->anr.transform.yreset + height > IPU3_UAPI_ANR_MAX_RESET) 2365 acc->anr.transform.yreset = IPU3_UAPI_ANR_MAX_RESET - height; 2366 if (acc->anr.transform.yreset < IPU3_UAPI_ANR_MIN_RESET) 2367 acc->anr.transform.yreset = IPU3_UAPI_ANR_MIN_RESET; 2368 2369 /* acc_param: awb_fr_config */ 2370 2371 if (use && use->acc_awb_fr) { 2372 /* Take values from user */ 2373 acc->awb_fr.config = acc_user->awb_fr; 2374 } else if (acc_old) { 2375 /* Use old value */ 2376 acc->awb_fr.config = acc_old->awb_fr.config; 2377 } else { 2378 /* Set from scratch */ 2379 acc->awb_fr.config = imgu_css_awb_fr_defaults; 2380 } 2381 2382 imgu_css_grid_end_calc(&acc->awb_fr.config.grid_cfg); 2383 2384 if (acc->awb_fr.config.grid_cfg.width <= 0) 2385 return -EINVAL; 2386 2387 acc->awb_fr.config.grid_cfg.height_per_slice = 2388 IMGU_ABI_AWB_FR_MAX_CELLS_PER_SET / 2389 acc->awb_fr.config.grid_cfg.width; 2390 2391 for (i = 0; i < stripes; i++) 2392 acc->awb_fr.stripes[i] = acc->awb_fr.config; 2393 2394 if (acc->awb_fr.config.grid_cfg.x_start >= 2395 acc->stripe.down_scaled_stripes[1].offset + min_overlap) { 2396 /* Enable only for rightmost stripe, disable left */ 2397 acc->awb_fr.stripes[0].grid_cfg.y_start &= 2398 ~IPU3_UAPI_GRID_Y_START_EN; 2399 } else if (acc->awb_fr.config.grid_cfg.x_end <= 2400 acc->stripe.bds_out_stripes[0].width - min_overlap) { 2401 /* Enable only for leftmost stripe, disable right */ 2402 acc->awb_fr.stripes[1].grid_cfg.y_start &= 2403 ~IPU3_UAPI_GRID_Y_START_EN; 2404 } else { 2405 /* Enable for both stripes */ 2406 u16 end; /* width for grid end */ 2407 2408 acc->awb_fr.stripes[0].grid_cfg.width = 2409 (acc->stripe.bds_out_stripes[0].width - min_overlap - 2410 acc->awb_fr.config.grid_cfg.x_start + 1) >> 2411 acc->awb_fr.config.grid_cfg.block_width_log2; 2412 acc->awb_fr.stripes[1].grid_cfg.width = 2413 acc->awb_fr.config.grid_cfg.width - 2414 acc->awb_fr.stripes[0].grid_cfg.width; 2415 2416 b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2; 2417 end = imgu_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start, 2418 acc->awb_fr.stripes[0].grid_cfg.width, 2419 b_w_log2); 2420 acc->awb_fr.stripes[0].grid_cfg.x_end = end; 2421 2422 acc->awb_fr.stripes[1].grid_cfg.x_start = 2423 (acc->awb_fr.stripes[0].grid_cfg.x_end + 1 - 2424 acc->stripe.down_scaled_stripes[1].offset) & 2425 IPU3_UAPI_GRID_START_MASK; 2426 b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2; 2427 end = imgu_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start, 2428 acc->awb_fr.stripes[1].grid_cfg.width, 2429 b_w_log2); 2430 acc->awb_fr.stripes[1].grid_cfg.x_end = end; 2431 2432 /* 2433 * To reduce complexity of debubbling and loading 2434 * statistics fix grid_height_per_slice to 1 for both 2435 * stripes. 2436 */ 2437 for (i = 0; i < stripes; i++) 2438 acc->awb_fr.stripes[i].grid_cfg.height_per_slice = 1; 2439 } 2440 2441 if (imgu_css_awb_fr_ops_calc(css, pipe, &acc->awb_fr)) 2442 return -EINVAL; 2443 2444 /* acc_param: ae_config */ 2445 2446 if (use && use->acc_ae) { 2447 /* Take values from user */ 2448 acc->ae.grid_cfg = acc_user->ae.grid_cfg; 2449 acc->ae.ae_ccm = acc_user->ae.ae_ccm; 2450 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++) 2451 acc->ae.weights[i] = acc_user->ae.weights[i]; 2452 } else if (acc_old) { 2453 /* Use old value */ 2454 acc->ae.grid_cfg = acc_old->ae.grid_cfg; 2455 acc->ae.ae_ccm = acc_old->ae.ae_ccm; 2456 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++) 2457 acc->ae.weights[i] = acc_old->ae.weights[i]; 2458 } else { 2459 /* Set from scratch */ 2460 static const struct ipu3_uapi_ae_weight_elem 2461 weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 }; 2462 2463 acc->ae.grid_cfg = imgu_css_ae_grid_defaults; 2464 acc->ae.ae_ccm = imgu_css_ae_ccm_defaults; 2465 for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++) 2466 acc->ae.weights[i] = weight_def; 2467 } 2468 2469 b_w_log2 = acc->ae.grid_cfg.block_width_log2; 2470 acc->ae.grid_cfg.x_end = imgu_css_grid_end(acc->ae.grid_cfg.x_start, 2471 acc->ae.grid_cfg.width, 2472 b_w_log2); 2473 b_w_log2 = acc->ae.grid_cfg.block_height_log2; 2474 acc->ae.grid_cfg.y_end = imgu_css_grid_end(acc->ae.grid_cfg.y_start, 2475 acc->ae.grid_cfg.height, 2476 b_w_log2); 2477 2478 for (i = 0; i < stripes; i++) 2479 acc->ae.stripes[i].grid = acc->ae.grid_cfg; 2480 2481 if (acc->ae.grid_cfg.x_start >= 2482 acc->stripe.down_scaled_stripes[1].offset) { 2483 /* Enable only for rightmost stripe, disable left */ 2484 acc->ae.stripes[0].grid.ae_en = 0; 2485 } else if (acc->ae.grid_cfg.x_end <= 2486 acc->stripe.bds_out_stripes[0].width) { 2487 /* Enable only for leftmost stripe, disable right */ 2488 acc->ae.stripes[1].grid.ae_en = 0; 2489 } else { 2490 /* Enable for both stripes */ 2491 u8 b_w_log2; 2492 2493 acc->ae.stripes[0].grid.width = 2494 (acc->stripe.bds_out_stripes[0].width - 2495 acc->ae.grid_cfg.x_start + 1) >> 2496 acc->ae.grid_cfg.block_width_log2; 2497 2498 acc->ae.stripes[1].grid.width = 2499 acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width; 2500 2501 b_w_log2 = acc->ae.stripes[0].grid.block_width_log2; 2502 acc->ae.stripes[0].grid.x_end = 2503 imgu_css_grid_end(acc->ae.stripes[0].grid.x_start, 2504 acc->ae.stripes[0].grid.width, 2505 b_w_log2); 2506 2507 acc->ae.stripes[1].grid.x_start = 2508 (acc->ae.stripes[0].grid.x_end + 1 - 2509 acc->stripe.down_scaled_stripes[1].offset) & 2510 IPU3_UAPI_GRID_START_MASK; 2511 b_w_log2 = acc->ae.stripes[1].grid.block_width_log2; 2512 acc->ae.stripes[1].grid.x_end = 2513 imgu_css_grid_end(acc->ae.stripes[1].grid.x_start, 2514 acc->ae.stripes[1].grid.width, 2515 b_w_log2); 2516 } 2517 2518 /* acc_param: af_config */ 2519 2520 if (use && use->acc_af) { 2521 /* Take values from user */ 2522 acc->af.config.filter_config = acc_user->af.filter_config; 2523 acc->af.config.grid_cfg = acc_user->af.grid_cfg; 2524 } else if (acc_old) { 2525 /* Use old value */ 2526 acc->af.config = acc_old->af.config; 2527 } else { 2528 /* Set from scratch */ 2529 acc->af.config.filter_config = 2530 imgu_css_af_defaults.filter_config; 2531 acc->af.config.grid_cfg = imgu_css_af_defaults.grid_cfg; 2532 } 2533 2534 imgu_css_grid_end_calc(&acc->af.config.grid_cfg); 2535 2536 if (acc->af.config.grid_cfg.width <= 0) 2537 return -EINVAL; 2538 2539 acc->af.config.grid_cfg.height_per_slice = 2540 IMGU_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width; 2541 acc->af.config.frame_size.width = 2542 ALIGN(css_pipe->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN); 2543 acc->af.config.frame_size.height = 2544 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2545 2546 if (acc->stripe.bds_out_stripes[0].width <= min_overlap) 2547 return -EINVAL; 2548 2549 for (i = 0; i < stripes; i++) { 2550 acc->af.stripes[i].grid_cfg = acc->af.config.grid_cfg; 2551 acc->af.stripes[i].frame_size.height = 2552 css_pipe->rect[IPU3_CSS_RECT_BDS].height; 2553 acc->af.stripes[i].frame_size.width = 2554 acc->stripe.bds_out_stripes[i].width; 2555 } 2556 2557 if (acc->af.config.grid_cfg.x_start >= 2558 acc->stripe.down_scaled_stripes[1].offset + min_overlap) { 2559 /* Enable only for rightmost stripe, disable left */ 2560 acc->af.stripes[0].grid_cfg.y_start &= 2561 ~IPU3_UAPI_GRID_Y_START_EN; 2562 } else if (acc->af.config.grid_cfg.x_end <= 2563 acc->stripe.bds_out_stripes[0].width - min_overlap) { 2564 /* Enable only for leftmost stripe, disable right */ 2565 acc->af.stripes[1].grid_cfg.y_start &= 2566 ~IPU3_UAPI_GRID_Y_START_EN; 2567 } else { 2568 /* Enable for both stripes */ 2569 2570 acc->af.stripes[0].grid_cfg.width = 2571 (acc->stripe.bds_out_stripes[0].width - min_overlap - 2572 acc->af.config.grid_cfg.x_start + 1) >> 2573 acc->af.config.grid_cfg.block_width_log2; 2574 acc->af.stripes[1].grid_cfg.width = 2575 acc->af.config.grid_cfg.width - 2576 acc->af.stripes[0].grid_cfg.width; 2577 2578 b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2; 2579 acc->af.stripes[0].grid_cfg.x_end = 2580 imgu_css_grid_end(acc->af.stripes[0].grid_cfg.x_start, 2581 acc->af.stripes[0].grid_cfg.width, 2582 b_w_log2); 2583 2584 acc->af.stripes[1].grid_cfg.x_start = 2585 (acc->af.stripes[0].grid_cfg.x_end + 1 - 2586 acc->stripe.down_scaled_stripes[1].offset) & 2587 IPU3_UAPI_GRID_START_MASK; 2588 2589 b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2; 2590 acc->af.stripes[1].grid_cfg.x_end = 2591 imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start, 2592 acc->af.stripes[1].grid_cfg.width, 2593 b_w_log2); 2594 2595 /* 2596 * To reduce complexity of debubbling and loading statistics 2597 * fix grid_height_per_slice to 1 for both stripes 2598 */ 2599 for (i = 0; i < stripes; i++) 2600 acc->af.stripes[i].grid_cfg.height_per_slice = 1; 2601 } 2602 2603 if (imgu_css_af_ops_calc(css, pipe, &acc->af)) 2604 return -EINVAL; 2605 2606 /* acc_param: awb_config */ 2607 2608 if (use && use->acc_awb) { 2609 /* Take values from user */ 2610 acc->awb.config = acc_user->awb.config; 2611 } else if (acc_old) { 2612 /* Use old value */ 2613 acc->awb.config = acc_old->awb.config; 2614 } else { 2615 /* Set from scratch */ 2616 acc->awb.config = imgu_css_awb_defaults; 2617 } 2618 2619 if (acc->awb.config.grid.width <= 0) 2620 return -EINVAL; 2621 2622 acc->awb.config.grid.height_per_slice = 2623 IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width, 2624 imgu_css_grid_end_calc(&acc->awb.config.grid); 2625 2626 for (i = 0; i < stripes; i++) 2627 acc->awb.stripes[i] = acc->awb.config; 2628 2629 if (acc->awb.config.grid.x_start >= 2630 acc->stripe.down_scaled_stripes[1].offset + min_overlap) { 2631 /* Enable only for rightmost stripe, disable left */ 2632 acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN; 2633 } else if (acc->awb.config.grid.x_end <= 2634 acc->stripe.bds_out_stripes[0].width - min_overlap) { 2635 /* Enable only for leftmost stripe, disable right */ 2636 acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN; 2637 } else { 2638 /* Enable for both stripes */ 2639 2640 acc->awb.stripes[0].grid.width = 2641 (acc->stripe.bds_out_stripes[0].width - 2642 acc->awb.config.grid.x_start + 1) >> 2643 acc->awb.config.grid.block_width_log2; 2644 acc->awb.stripes[1].grid.width = acc->awb.config.grid.width - 2645 acc->awb.stripes[0].grid.width; 2646 2647 b_w_log2 = acc->awb.stripes[0].grid.block_width_log2; 2648 acc->awb.stripes[0].grid.x_end = 2649 imgu_css_grid_end(acc->awb.stripes[0].grid.x_start, 2650 acc->awb.stripes[0].grid.width, 2651 b_w_log2); 2652 2653 acc->awb.stripes[1].grid.x_start = 2654 (acc->awb.stripes[0].grid.x_end + 1 - 2655 acc->stripe.down_scaled_stripes[1].offset) & 2656 IPU3_UAPI_GRID_START_MASK; 2657 2658 b_w_log2 = acc->awb.stripes[1].grid.block_width_log2; 2659 acc->awb.stripes[1].grid.x_end = 2660 imgu_css_grid_end(acc->awb.stripes[1].grid.x_start, 2661 acc->awb.stripes[1].grid.width, 2662 b_w_log2); 2663 2664 /* 2665 * To reduce complexity of debubbling and loading statistics 2666 * fix grid_height_per_slice to 1 for both stripes 2667 */ 2668 for (i = 0; i < stripes; i++) 2669 acc->awb.stripes[i].grid.height_per_slice = 1; 2670 } 2671 2672 if (imgu_css_awb_ops_calc(css, pipe, &acc->awb)) 2673 return -EINVAL; 2674 2675 return 0; 2676 } 2677 2678 /* 2679 * Fill the indicated structure in `new_binary_params' from the possible 2680 * sources based on `use_user' flag: if the flag is false, copy from 2681 * `old_binary_params', or if the flag is true, copy from `user_setting' 2682 * and return NULL (or error pointer on error). 2683 * If the flag is false and `old_binary_params' is NULL, return pointer 2684 * to the structure inside `new_binary_params'. In that case the caller 2685 * should calculate and fill the structure from scratch. 2686 */ 2687 static void *imgu_css_cfg_copy(struct imgu_css *css, 2688 unsigned int pipe, bool use_user, 2689 void *user_setting, void *old_binary_params, 2690 void *new_binary_params, 2691 enum imgu_abi_memories m, 2692 struct imgu_fw_isp_parameter *par, 2693 size_t par_size) 2694 { 2695 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM; 2696 void *new_setting, *old_setting; 2697 2698 new_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par, 2699 par_size, new_binary_params); 2700 if (!new_setting) 2701 return ERR_PTR(-EPROTO); /* Corrupted firmware */ 2702 2703 if (use_user) { 2704 /* Take new user parameters */ 2705 memcpy(new_setting, user_setting, par_size); 2706 } else if (old_binary_params) { 2707 /* Take previous value */ 2708 old_setting = imgu_css_fw_pipeline_params(css, pipe, c, m, par, 2709 par_size, 2710 old_binary_params); 2711 if (!old_setting) 2712 return ERR_PTR(-EPROTO); 2713 memcpy(new_setting, old_setting, par_size); 2714 } else { 2715 return new_setting; /* Need to calculate */ 2716 } 2717 2718 return NULL; /* Copied from other value */ 2719 } 2720 2721 /* 2722 * Configure VMEM0 parameters (late binding parameters). 2723 */ 2724 int imgu_css_cfg_vmem0(struct imgu_css *css, unsigned int pipe, 2725 struct ipu3_uapi_flags *use, 2726 void *vmem0, void *vmem0_old, 2727 struct ipu3_uapi_params *user) 2728 { 2729 const struct imgu_fw_info *bi = 2730 &css->fwp->binary_header[css->pipes[pipe].bindex]; 2731 struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp + 2732 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]; 2733 struct ipu3_uapi_isp_lin_vmem_params *lin_vmem = NULL; 2734 struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem = NULL; 2735 struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem = NULL; 2736 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM; 2737 const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0; 2738 unsigned int i; 2739 2740 /* Configure VMEM0 */ 2741 2742 memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size); 2743 2744 /* Configure Linearization VMEM0 parameters */ 2745 2746 lin_vmem = imgu_css_cfg_copy(css, pipe, use && use->lin_vmem_params, 2747 &user->lin_vmem_params, vmem0_old, vmem0, 2748 m, &pofs->vmem.lin, sizeof(*lin_vmem)); 2749 if (!IS_ERR_OR_NULL(lin_vmem)) { 2750 /* Generate parameter from scratch */ 2751 for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) { 2752 lin_vmem->lin_lutlow_gr[i] = 32 * i; 2753 lin_vmem->lin_lutlow_r[i] = 32 * i; 2754 lin_vmem->lin_lutlow_b[i] = 32 * i; 2755 lin_vmem->lin_lutlow_gb[i] = 32 * i; 2756 2757 lin_vmem->lin_lutdif_gr[i] = 32; 2758 lin_vmem->lin_lutdif_r[i] = 32; 2759 lin_vmem->lin_lutdif_b[i] = 32; 2760 lin_vmem->lin_lutdif_gb[i] = 32; 2761 } 2762 } 2763 2764 /* Configure TNR3 VMEM parameters */ 2765 if (css->pipes[pipe].pipe_id == IPU3_CSS_PIPE_ID_VIDEO) { 2766 tnr_vmem = imgu_css_cfg_copy(css, pipe, 2767 use && use->tnr3_vmem_params, 2768 &user->tnr3_vmem_params, 2769 vmem0_old, vmem0, m, 2770 &pofs->vmem.tnr3, 2771 sizeof(*tnr_vmem)); 2772 if (!IS_ERR_OR_NULL(tnr_vmem)) { 2773 /* Generate parameter from scratch */ 2774 for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++) 2775 tnr_vmem->sigma[i] = 256; 2776 } 2777 } 2778 i = IPU3_UAPI_ISP_TNR3_VMEM_LEN; 2779 2780 /* Configure XNR3 VMEM parameters */ 2781 2782 xnr_vmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_vmem_params, 2783 &user->xnr3_vmem_params, vmem0_old, vmem0, 2784 m, &pofs->vmem.xnr3, sizeof(*xnr_vmem)); 2785 if (!IS_ERR_OR_NULL(xnr_vmem)) { 2786 xnr_vmem->x[i] = imgu_css_xnr3_vmem_defaults.x 2787 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2788 xnr_vmem->a[i] = imgu_css_xnr3_vmem_defaults.a 2789 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2790 xnr_vmem->b[i] = imgu_css_xnr3_vmem_defaults.b 2791 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2792 xnr_vmem->c[i] = imgu_css_xnr3_vmem_defaults.c 2793 [i % IMGU_XNR3_VMEM_LUT_LEN]; 2794 } 2795 2796 return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ? 2797 -EPROTO : 0; 2798 } 2799 2800 /* 2801 * Configure DMEM0 parameters (late binding parameters). 2802 */ 2803 int imgu_css_cfg_dmem0(struct imgu_css *css, unsigned int pipe, 2804 struct ipu3_uapi_flags *use, 2805 void *dmem0, void *dmem0_old, 2806 struct ipu3_uapi_params *user) 2807 { 2808 struct imgu_css_pipe *css_pipe = &css->pipes[pipe]; 2809 const struct imgu_fw_info *bi = 2810 &css->fwp->binary_header[css_pipe->bindex]; 2811 struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp + 2812 bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]; 2813 2814 struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL; 2815 struct ipu3_uapi_isp_xnr3_params *xnr_dmem; 2816 2817 const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM; 2818 const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0; 2819 2820 /* Configure DMEM0 */ 2821 2822 memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size); 2823 2824 /* Configure TNR3 DMEM0 parameters */ 2825 if (css_pipe->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) { 2826 tnr_dmem = imgu_css_cfg_copy(css, pipe, 2827 use && use->tnr3_dmem_params, 2828 &user->tnr3_dmem_params, 2829 dmem0_old, dmem0, m, 2830 &pofs->dmem.tnr3, 2831 sizeof(*tnr_dmem)); 2832 if (!IS_ERR_OR_NULL(tnr_dmem)) { 2833 /* Generate parameter from scratch */ 2834 tnr_dmem->knee_y1 = 768; 2835 tnr_dmem->knee_y2 = 1280; 2836 } 2837 } 2838 2839 /* Configure XNR3 DMEM0 parameters */ 2840 2841 xnr_dmem = imgu_css_cfg_copy(css, pipe, use && use->xnr3_dmem_params, 2842 &user->xnr3_dmem_params, dmem0_old, dmem0, 2843 m, &pofs->dmem.xnr3, sizeof(*xnr_dmem)); 2844 if (!IS_ERR_OR_NULL(xnr_dmem)) { 2845 /* Generate parameter from scratch */ 2846 xnr_dmem->alpha.y0 = 2047; 2847 xnr_dmem->alpha.u0 = 2047; 2848 xnr_dmem->alpha.v0 = 2047; 2849 } 2850 2851 return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0; 2852 } 2853 2854 /* Generate unity morphing table without morphing effect */ 2855 void imgu_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc, 2856 int frame_in_x, int frame_in_y, 2857 int frame_out_x, int frame_out_y, 2858 int env_w, int env_h) 2859 { 2860 static const unsigned int FRAC_BITS = IMGU_ABI_GDC_FRAC_BITS; 2861 static const unsigned int XMEM_ALIGN = 1 << 4; 2862 const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1); 2863 static const unsigned int BCI_ENV = 4; 2864 static const unsigned int BYP = 2; /* Bytes per pixel */ 2865 const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + env_w + 1; 2866 const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + env_h + 1; 2867 2868 struct imgu_abi_gdc_warp_param gdc_luma, gdc_chroma; 2869 2870 unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x, 2871 IMGU_DVS_BLOCK_W), 2); 2872 unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H); 2873 unsigned int y0, x0, x1, x, y; 2874 2875 /* Global luma settings */ 2876 gdc_luma.origin_x = 0; 2877 gdc_luma.origin_y = 0; 2878 gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << FRAC_BITS; 2879 gdc_luma.p0_y = 0; 2880 gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS); 2881 gdc_luma.p1_y = gdc_luma.p0_y; 2882 gdc_luma.p2_x = gdc_luma.p0_x; 2883 gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << FRAC_BITS); 2884 gdc_luma.p3_x = gdc_luma.p1_x; 2885 gdc_luma.p3_y = gdc_luma.p2_y; 2886 2887 gdc_luma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV + 2888 OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK); 2889 gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width, 2890 IPU3_UAPI_ISP_VEC_ELEMS); 2891 gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width, 2892 IMGU_ABI_ISP_DDR_WORD_BYTES / 2893 BYP); 2894 gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV; 2895 gdc_luma.padding = 0; 2896 2897 /* Global chroma settings */ 2898 gdc_chroma.origin_x = 0; 2899 gdc_chroma.origin_y = 0; 2900 gdc_chroma.p0_x = (OFFSET_X / 2 - (OFFSET_X / 2 & XMEM_ALIGN_MASK)) << 2901 FRAC_BITS; 2902 gdc_chroma.p0_y = 0; 2903 gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << FRAC_BITS); 2904 gdc_chroma.p1_y = gdc_chroma.p0_y; 2905 gdc_chroma.p2_x = gdc_chroma.p0_x; 2906 gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << FRAC_BITS); 2907 gdc_chroma.p3_x = gdc_chroma.p1_x; 2908 gdc_chroma.p3_y = gdc_chroma.p2_y; 2909 2910 gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV; 2911 gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width, 2912 IPU3_UAPI_ISP_VEC_ELEMS); 2913 gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width, 2914 IMGU_ABI_ISP_DDR_WORD_BYTES / 2915 BYP); 2916 gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV; 2917 gdc_chroma.padding = 0; 2918 2919 /* Calculate block offsets for luma and chroma */ 2920 for (y0 = 0; y0 < blocks_y; y0++) { 2921 for (x0 = 0; x0 < blocks_x / 2; x0++) { 2922 for (x1 = 0; x1 < 2; x1++) { 2923 /* Luma blocks */ 2924 x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X; 2925 x &= XMEM_ALIGN_MASK; 2926 y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y; 2927 *gdc = gdc_luma; 2928 gdc->in_addr_offset = 2929 (y * frame_in_x + x) * BYP; 2930 gdc++; 2931 } 2932 2933 /* Chroma block */ 2934 x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2; 2935 x &= XMEM_ALIGN_MASK; 2936 y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2; 2937 *gdc = gdc_chroma; 2938 gdc->in_addr_offset = (y * frame_in_x + x) * BYP; 2939 gdc++; 2940 } 2941 } 2942 } 2943