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