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