linux/drivers/staging/media/davinci_vpfe/dm365_resizer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2012 Texas Instruments Inc
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation version 2.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * Contributors:
  15 *      Manjunath Hadli <manjunath.hadli@ti.com>
  16 *      Prabhakar Lad <prabhakar.lad@ti.com>
  17 *
  18 *
  19 * Resizer allows upscaling or downscaling a image to a desired
  20 * resolution. There are 2 resizer modules. both operating on the
  21 * same input image, but can have different output resolution.
  22 */
  23
  24#include "dm365_ipipe_hw.h"
  25#include "dm365_resizer.h"
  26
  27#define MIN_IN_WIDTH            32
  28#define MIN_IN_HEIGHT           32
  29#define MAX_IN_WIDTH            4095
  30#define MAX_IN_HEIGHT           4095
  31#define MIN_OUT_WIDTH           16
  32#define MIN_OUT_HEIGHT          2
  33
  34static const unsigned int resizer_input_formats[] = {
  35        MEDIA_BUS_FMT_UYVY8_2X8,
  36        MEDIA_BUS_FMT_Y8_1X8,
  37        MEDIA_BUS_FMT_UV8_1X8,
  38        MEDIA_BUS_FMT_SGRBG12_1X12,
  39};
  40
  41static const unsigned int resizer_output_formats[] = {
  42        MEDIA_BUS_FMT_UYVY8_2X8,
  43        MEDIA_BUS_FMT_Y8_1X8,
  44        MEDIA_BUS_FMT_UV8_1X8,
  45        MEDIA_BUS_FMT_YDYUYDYV8_1X16,
  46        MEDIA_BUS_FMT_SGRBG12_1X12,
  47};
  48
  49/* resizer_calculate_line_length() - This function calculates the line length of
  50 *                                   various image planes at the input and
  51 *                                   output.
  52 */
  53static void
  54resizer_calculate_line_length(u32 pix, int width, int height,
  55                              int *line_len, int *line_len_c)
  56{
  57        *line_len = 0;
  58        *line_len_c = 0;
  59
  60        if (pix == MEDIA_BUS_FMT_UYVY8_2X8 ||
  61            pix == MEDIA_BUS_FMT_SGRBG12_1X12) {
  62                *line_len = width << 1;
  63        } else {
  64                *line_len = width;
  65                *line_len_c = width;
  66        }
  67
  68        /* adjust the line len to be a multiple of 32 */
  69        *line_len += 31;
  70        *line_len &= ~0x1f;
  71        *line_len_c += 31;
  72        *line_len_c &= ~0x1f;
  73}
  74
  75static inline int
  76resizer_validate_output_image_format(struct device *dev,
  77                                     struct v4l2_mbus_framefmt *format,
  78                                     int *in_line_len, int *in_line_len_c)
  79{
  80        if (format->code != MEDIA_BUS_FMT_UYVY8_2X8 &&
  81            format->code != MEDIA_BUS_FMT_Y8_1X8 &&
  82            format->code != MEDIA_BUS_FMT_UV8_1X8 &&
  83            format->code != MEDIA_BUS_FMT_YDYUYDYV8_1X16 &&
  84            format->code != MEDIA_BUS_FMT_SGRBG12_1X12) {
  85                dev_err(dev, "Invalid Mbus format, %d\n", format->code);
  86                return -EINVAL;
  87        }
  88        if (!format->width || !format->height) {
  89                dev_err(dev, "invalid width or height\n");
  90                return -EINVAL;
  91        }
  92        resizer_calculate_line_length(format->code, format->width,
  93                format->height, in_line_len, in_line_len_c);
  94        return 0;
  95}
  96
  97static void
  98resizer_configure_passthru(struct vpfe_resizer_device *resizer, int bypass)
  99{
 100        struct resizer_params *param = &resizer->config;
 101
 102        param->rsz_rsc_param[RSZ_A].cen = DISABLE;
 103        param->rsz_rsc_param[RSZ_A].yen = DISABLE;
 104        param->rsz_rsc_param[RSZ_A].v_phs_y = 0;
 105        param->rsz_rsc_param[RSZ_A].v_phs_c = 0;
 106        param->rsz_rsc_param[RSZ_A].v_dif = 256;
 107        param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0;
 108        param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0;
 109        param->rsz_rsc_param[RSZ_A].h_phs = 0;
 110        param->rsz_rsc_param[RSZ_A].h_dif = 256;
 111        param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0;
 112        param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0;
 113        param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE;
 114        param->rsz2rgb[RSZ_A].rgb_en = DISABLE;
 115        param->rsz_en[RSZ_A] = ENABLE;
 116        param->rsz_en[RSZ_B] = DISABLE;
 117        if (bypass) {
 118                param->rsz_rsc_param[RSZ_A].i_vps = 0;
 119                param->rsz_rsc_param[RSZ_A].i_hps = 0;
 120                /* Raw Bypass */
 121                param->rsz_common.passthrough = BYPASS_ON;
 122        }
 123}
 124
 125static void
 126configure_resizer_out_params(struct vpfe_resizer_device *resizer, int index,
 127                             void *output_spec, unsigned char partial,
 128                             unsigned int flag)
 129{
 130        struct resizer_params *param = &resizer->config;
 131        struct v4l2_mbus_framefmt *outformat;
 132        struct vpfe_rsz_output_spec *output;
 133
 134        if (index == RSZ_A &&
 135            resizer->resizer_a.output == RESIZER_OUTPUT_NONE) {
 136                param->rsz_en[index] = DISABLE;
 137                return;
 138        }
 139        if (index == RSZ_B &&
 140            resizer->resizer_b.output == RESIZER_OUTPUT_NONE) {
 141                param->rsz_en[index] = DISABLE;
 142                return;
 143        }
 144        output = output_spec;
 145        param->rsz_en[index] = ENABLE;
 146        if (partial) {
 147                param->rsz_rsc_param[index].h_flip = output->h_flip;
 148                param->rsz_rsc_param[index].v_flip = output->v_flip;
 149                param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
 150                param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
 151                param->rsz_rsc_param[index].v_lpf_int_y =
 152                                                output->v_lpf_int_y;
 153                param->rsz_rsc_param[index].v_lpf_int_c =
 154                                                output->v_lpf_int_c;
 155                param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
 156                param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
 157                param->rsz_rsc_param[index].h_lpf_int_y =
 158                                                output->h_lpf_int_y;
 159                param->rsz_rsc_param[index].h_lpf_int_c =
 160                                                output->h_lpf_int_c;
 161                param->rsz_rsc_param[index].dscale_en =
 162                                                output->en_down_scale;
 163                param->rsz_rsc_param[index].h_dscale_ave_sz =
 164                                                output->h_dscale_ave_sz;
 165                param->rsz_rsc_param[index].v_dscale_ave_sz =
 166                                                output->v_dscale_ave_sz;
 167                param->ext_mem_param[index].user_y_ofst =
 168                                    (output->user_y_ofst + 31) & ~0x1f;
 169                param->ext_mem_param[index].user_c_ofst =
 170                                    (output->user_c_ofst + 31) & ~0x1f;
 171                return;
 172        }
 173
 174        if (index == RSZ_A)
 175                outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
 176        else
 177                outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
 178        param->rsz_rsc_param[index].o_vsz = outformat->height - 1;
 179        param->rsz_rsc_param[index].o_hsz = outformat->width - 1;
 180        param->ext_mem_param[index].rsz_sdr_ptr_s_y = output->vst_y;
 181        param->ext_mem_param[index].rsz_sdr_ptr_e_y = outformat->height;
 182        param->ext_mem_param[index].rsz_sdr_ptr_s_c = output->vst_c;
 183        param->ext_mem_param[index].rsz_sdr_ptr_e_c = outformat->height;
 184
 185        if (!flag)
 186                return;
 187        /* update common parameters */
 188        param->rsz_rsc_param[index].h_flip = output->h_flip;
 189        param->rsz_rsc_param[index].v_flip = output->v_flip;
 190        param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
 191        param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
 192        param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y;
 193        param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c;
 194        param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
 195        param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
 196        param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y;
 197        param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c;
 198        param->rsz_rsc_param[index].dscale_en = output->en_down_scale;
 199        param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz;
 200        param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz;
 201        param->ext_mem_param[index].user_y_ofst =
 202                                        (output->user_y_ofst + 31) & ~0x1f;
 203        param->ext_mem_param[index].user_c_ofst =
 204                                        (output->user_c_ofst + 31) & ~0x1f;
 205}
 206
 207/*
 208 * resizer_calculate_resize_ratios() - Calculates resize ratio for resizer
 209 *                                    A or B. This is called after setting
 210 *                                   the input size or output size.
 211 * @resizer: Pointer to VPFE resizer subdevice.
 212 * @index: index RSZ_A-resizer-A RSZ_B-resizer-B.
 213 */
 214static void
 215resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index)
 216{
 217        struct resizer_params *param = &resizer->config;
 218        struct v4l2_mbus_framefmt *informat, *outformat;
 219
 220        informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
 221
 222        if (index == RSZ_A)
 223                outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
 224        else
 225                outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
 226
 227        if (outformat->field != V4L2_FIELD_INTERLACED)
 228                param->rsz_rsc_param[index].v_dif =
 229                        ((informat->height) * 256) / (outformat->height);
 230        else
 231                param->rsz_rsc_param[index].v_dif =
 232                        ((informat->height >> 1) * 256) / (outformat->height);
 233        param->rsz_rsc_param[index].h_dif =
 234                        ((informat->width) * 256) / (outformat->width);
 235}
 236
 237static void resizer_enable_422_420_conversion(struct resizer_params *param,
 238                                              int index, bool en)
 239{
 240        param->rsz_rsc_param[index].cen = en;
 241        param->rsz_rsc_param[index].yen = en;
 242}
 243
 244/* resizer_calculate_sdram_offsets() - This function calculates the offsets from
 245 *                                     start of buffer for the C plane when
 246 *                                     output format is YUV420SP. It also
 247 *                                     calculates the offsets from the start of
 248 *                                     the buffer when the image is flipped
 249 *                                     vertically or horizontally for ycbcr/y/c
 250 *                                     planes.
 251 * @resizer: Pointer to resizer subdevice.
 252 * @index: index RSZ_A-resizer-A RSZ_B-resizer-B.
 253 */
 254static int
 255resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index)
 256{
 257        struct resizer_params *param = &resizer->config;
 258        struct v4l2_mbus_framefmt *outformat;
 259        int bytesperpixel = 2;
 260        int image_height;
 261        int image_width;
 262        int yuv_420 = 0;
 263        int offset = 0;
 264
 265        if (index == RSZ_A)
 266                outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
 267        else
 268                outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
 269
 270        image_height = outformat->height + 1;
 271        image_width = outformat->width + 1;
 272        param->ext_mem_param[index].c_offset = 0;
 273        param->ext_mem_param[index].flip_ofst_y = 0;
 274        param->ext_mem_param[index].flip_ofst_c = 0;
 275        if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) {
 276                /* YUV 420 */
 277                yuv_420 = 1;
 278                bytesperpixel = 1;
 279        }
 280
 281        if (param->rsz_rsc_param[index].h_flip)
 282                /* width * bytesperpixel - 1 */
 283                offset = (image_width * bytesperpixel) - 1;
 284        if (param->rsz_rsc_param[index].v_flip)
 285                offset += (image_height - 1) *
 286                        param->ext_mem_param[index].rsz_sdr_oft_y;
 287        param->ext_mem_param[index].flip_ofst_y = offset;
 288        if (!yuv_420)
 289                return 0;
 290        offset = 0;
 291        /* half height for c-plane */
 292        if (param->rsz_rsc_param[index].h_flip)
 293                /* width * bytesperpixel - 1 */
 294                offset = image_width - 1;
 295        if (param->rsz_rsc_param[index].v_flip)
 296                offset += (((image_height >> 1) - 1) *
 297                           param->ext_mem_param[index].rsz_sdr_oft_c);
 298        param->ext_mem_param[index].flip_ofst_c = offset;
 299        param->ext_mem_param[index].c_offset =
 300                      param->ext_mem_param[index].rsz_sdr_oft_y * image_height;
 301        return 0;
 302}
 303
 304static int resizer_configure_output_win(struct vpfe_resizer_device *resizer)
 305{
 306        struct resizer_params *param = &resizer->config;
 307        struct vpfe_rsz_output_spec output_specs;
 308        struct v4l2_mbus_framefmt *outformat;
 309        int line_len_c;
 310        int line_len;
 311        int ret;
 312
 313        outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
 314
 315        memset(&output_specs, 0x0, sizeof(struct vpfe_rsz_output_spec));
 316        output_specs.vst_y = param->user_config.vst;
 317        if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
 318                output_specs.vst_c = param->user_config.vst;
 319
 320        configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0);
 321        resizer_calculate_line_length(outformat->code,
 322                                      param->rsz_rsc_param[0].o_hsz + 1,
 323                                      param->rsz_rsc_param[0].o_vsz + 1,
 324                                      &line_len, &line_len_c);
 325        param->ext_mem_param[0].rsz_sdr_oft_y = line_len;
 326        param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c;
 327        resizer_calculate_resize_ratios(resizer, RSZ_A);
 328        if (param->rsz_en[RSZ_B])
 329                resizer_calculate_resize_ratios(resizer, RSZ_B);
 330
 331        if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
 332                resizer_enable_422_420_conversion(param, RSZ_A, ENABLE);
 333        else
 334                resizer_enable_422_420_conversion(param, RSZ_A, DISABLE);
 335
 336        ret = resizer_calculate_sdram_offsets(resizer, RSZ_A);
 337        if (!ret && param->rsz_en[RSZ_B])
 338                ret = resizer_calculate_sdram_offsets(resizer, RSZ_B);
 339
 340        if (ret)
 341                pr_err("Error in calculating sdram offsets\n");
 342        return ret;
 343}
 344
 345static int
 346resizer_calculate_down_scale_f_div_param(struct device *dev,
 347                                         int input_width, int output_width,
 348                                         struct resizer_scale_param *param)
 349{
 350        /* rsz = R, input_width = H, output width = h in the equation */
 351        unsigned int two_power;
 352        unsigned int upper_h1;
 353        unsigned int upper_h2;
 354        unsigned int val1;
 355        unsigned int val;
 356        unsigned int rsz;
 357        unsigned int h1;
 358        unsigned int h2;
 359        unsigned int o;
 360        unsigned int n;
 361
 362        upper_h1 = input_width >> 1;
 363        n = param->h_dscale_ave_sz;
 364        /* 2 ^ (scale+1) */
 365        two_power = 1 << (n + 1);
 366        upper_h1 = (upper_h1 >> (n + 1)) << (n + 1);
 367        upper_h2 = input_width - upper_h1;
 368        if (upper_h2 % two_power) {
 369                dev_err(dev, "frame halves to be a multiple of 2 power n+1\n");
 370                return -EINVAL;
 371        }
 372        two_power = 1 << n;
 373        rsz = (input_width << 8) / output_width;
 374        val = rsz * two_power;
 375        val = ((upper_h1 << 8) / val) + 1;
 376        if (!(val % 2)) {
 377                h1 = val;
 378        } else {
 379                val = upper_h1 << 8;
 380                val >>= n + 1;
 381                val -= rsz >> 1;
 382                val /= rsz << 1;
 383                val <<= 1;
 384                val += 2;
 385                h1 = val;
 386        }
 387        o = 10 + (two_power << 2);
 388        if (((input_width << 7) / rsz) % 2)
 389                o += ((DIV_ROUND_UP(rsz, 1024) << 1) << n);
 390        h2 = output_width - h1;
 391        /* phi */
 392        val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8);
 393        /* skip */
 394        val1 = ((val - 1024) >> 9) << 1;
 395        param->f_div.num_passes = MAX_PASSES;
 396        param->f_div.pass[0].o_hsz = h1 - 1;
 397        param->f_div.pass[0].i_hps = 0;
 398        param->f_div.pass[0].h_phs = 0;
 399        param->f_div.pass[0].src_hps = 0;
 400        param->f_div.pass[0].src_hsz = upper_h1 + o;
 401        param->f_div.pass[1].o_hsz = h2 - 1;
 402        param->f_div.pass[1].i_hps = 10 + (val1 * two_power);
 403        param->f_div.pass[1].h_phs = val - (val1 << 8);
 404        param->f_div.pass[1].src_hps = upper_h1 - o;
 405        param->f_div.pass[1].src_hsz = upper_h2 + o;
 406
 407        return 0;
 408}
 409
 410static int
 411resizer_configure_common_in_params(struct vpfe_resizer_device *resizer)
 412{
 413        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
 414        struct resizer_params *param = &resizer->config;
 415        struct vpfe_rsz_config_params *user_config;
 416        struct v4l2_mbus_framefmt *informat;
 417
 418        informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
 419        user_config = &resizer->config.user_config;
 420        param->rsz_common.vps = param->user_config.vst;
 421        param->rsz_common.hps = param->user_config.hst;
 422
 423        if (vpfe_ipipeif_decimation_enabled(vpfe_dev))
 424                param->rsz_common.hsz = ((informat->width - 1) *
 425                        IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev);
 426        else
 427                param->rsz_common.hsz = informat->width - 1;
 428
 429        if (informat->field == V4L2_FIELD_INTERLACED)
 430                param->rsz_common.vsz  = (informat->height - 1) >> 1;
 431        else
 432                param->rsz_common.vsz  = informat->height - 1;
 433
 434        param->rsz_common.raw_flip = 0;
 435
 436        if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF)
 437                param->rsz_common.source = IPIPEIF_DATA;
 438        else
 439                param->rsz_common.source = IPIPE_DATA;
 440
 441        switch (informat->code) {
 442        case MEDIA_BUS_FMT_UYVY8_2X8:
 443                param->rsz_common.src_img_fmt = RSZ_IMG_422;
 444                param->rsz_common.raw_flip = 0;
 445                break;
 446
 447        case MEDIA_BUS_FMT_Y8_1X8:
 448                param->rsz_common.src_img_fmt = RSZ_IMG_420;
 449                /* Select y */
 450                param->rsz_common.y_c = 0;
 451                param->rsz_common.raw_flip = 0;
 452                break;
 453
 454        case MEDIA_BUS_FMT_UV8_1X8:
 455                param->rsz_common.src_img_fmt = RSZ_IMG_420;
 456                /* Select y */
 457                param->rsz_common.y_c = 1;
 458                param->rsz_common.raw_flip = 0;
 459                break;
 460
 461        case MEDIA_BUS_FMT_SGRBG12_1X12:
 462                param->rsz_common.raw_flip = 1;
 463                break;
 464
 465        default:
 466                param->rsz_common.src_img_fmt = RSZ_IMG_422;
 467                param->rsz_common.source = IPIPE_DATA;
 468        }
 469
 470        param->rsz_common.yuv_y_min = user_config->yuv_y_min;
 471        param->rsz_common.yuv_y_max = user_config->yuv_y_max;
 472        param->rsz_common.yuv_c_min = user_config->yuv_c_min;
 473        param->rsz_common.yuv_c_max = user_config->yuv_c_max;
 474        param->rsz_common.out_chr_pos = user_config->out_chr_pos;
 475        param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even;
 476
 477        return 0;
 478}
 479static int
 480resizer_configure_in_continuous_mode(struct vpfe_resizer_device *resizer)
 481{
 482        struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
 483        struct resizer_params *param = &resizer->config;
 484        struct vpfe_rsz_config_params *cont_config;
 485        int line_len_c;
 486        int line_len;
 487        int ret;
 488
 489        if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) {
 490                dev_err(dev, "enable resizer - Resizer-A\n");
 491                return -EINVAL;
 492        }
 493
 494        cont_config = &resizer->config.user_config;
 495        param->rsz_en[RSZ_A] = ENABLE;
 496        configure_resizer_out_params(resizer, RSZ_A,
 497                                     &cont_config->output1, 1, 0);
 498        param->rsz_en[RSZ_B] = DISABLE;
 499        param->oper_mode = RESIZER_MODE_CONTINUOUS;
 500
 501        if (resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) {
 502                struct v4l2_mbus_framefmt *outformat2;
 503
 504                param->rsz_en[RSZ_B] = ENABLE;
 505                outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
 506                ret = resizer_validate_output_image_format(dev, outformat2,
 507                                &line_len, &line_len_c);
 508                if (ret)
 509                        return ret;
 510                param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
 511                param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
 512                configure_resizer_out_params(resizer, RSZ_B,
 513                                                &cont_config->output2, 0, 1);
 514                if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
 515                        resizer_enable_422_420_conversion(param,
 516                                                          RSZ_B, ENABLE);
 517                else
 518                        resizer_enable_422_420_conversion(param,
 519                                                          RSZ_B, DISABLE);
 520        }
 521        resizer_configure_common_in_params(resizer);
 522        ret = resizer_configure_output_win(resizer);
 523        if (ret)
 524                return ret;
 525
 526        param->rsz_common.passthrough = cont_config->bypass;
 527        if (cont_config->bypass)
 528                resizer_configure_passthru(resizer, 1);
 529
 530        return 0;
 531}
 532
 533static inline int
 534resizer_validate_input_image_format(struct device *dev,
 535                                    u32 pix,
 536                                    int width, int height, int *line_len)
 537{
 538        int val;
 539
 540        if (pix != MEDIA_BUS_FMT_UYVY8_2X8 &&
 541            pix != MEDIA_BUS_FMT_Y8_1X8 &&
 542            pix != MEDIA_BUS_FMT_UV8_1X8 &&
 543            pix != MEDIA_BUS_FMT_SGRBG12_1X12) {
 544                dev_err(dev,
 545                "resizer validate output: pix format not supported, %d\n", pix);
 546                return -EINVAL;
 547        }
 548
 549        if (!width || !height) {
 550                dev_err(dev,
 551                        "resizer validate input: invalid width or height\n");
 552                return -EINVAL;
 553        }
 554
 555        if (pix == MEDIA_BUS_FMT_UV8_1X8)
 556                resizer_calculate_line_length(pix, width,
 557                                              height, &val, line_len);
 558        else
 559                resizer_calculate_line_length(pix, width,
 560                                              height, line_len, &val);
 561
 562        return 0;
 563}
 564
 565static int
 566resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en,
 567                            unsigned char rsz, unsigned char frame_div_mode_en,
 568                            int width)
 569{
 570        if (dec_en && frame_div_mode_en) {
 571                dev_err(dev,
 572                 "dec_en & frame_div_mode_en can not enabled simultaneously\n");
 573                return -EINVAL;
 574        }
 575
 576        if (frame_div_mode_en) {
 577                dev_err(dev, "frame_div_mode mode not supported\n");
 578                return -EINVAL;
 579        }
 580
 581        if (!dec_en)
 582                return 0;
 583
 584        if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) {
 585                dev_err(dev,
 586                        "image width to be more than %d for decimation\n",
 587                        VPFE_IPIPE_MAX_INPUT_WIDTH);
 588                return -EINVAL;
 589        }
 590
 591        if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) {
 592                dev_err(dev, "rsz range is %d to %d\n",
 593                        IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
 594                return -EINVAL;
 595        }
 596
 597        return 0;
 598}
 599
 600/* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame
 601 *                                          division parameters for resizer.
 602 *                                          in normal mode.
 603 */
 604static int
 605resizer_calculate_normal_f_div_param(struct device *dev, int input_width,
 606                int output_width, struct resizer_scale_param *param)
 607{
 608        /* rsz = R, input_width = H, output width = h in the equation */
 609        unsigned int val1;
 610        unsigned int rsz;
 611        unsigned int val;
 612        unsigned int h1;
 613        unsigned int h2;
 614        unsigned int o;
 615
 616        if (output_width > input_width) {
 617                dev_err(dev, "frame div mode is used for scale down only\n");
 618                return -EINVAL;
 619        }
 620
 621        rsz = (input_width << 8) / output_width;
 622        val = rsz << 1;
 623        val = ((input_width << 8) / val) + 1;
 624        o = 14;
 625        if (!(val % 2)) {
 626                h1 = val;
 627        } else {
 628                val = input_width << 7;
 629                val -= rsz >> 1;
 630                val /= rsz << 1;
 631                val <<= 1;
 632                val += 2;
 633                o += (DIV_ROUND_UP(rsz, 1024) << 1);
 634                h1 = val;
 635        }
 636        h2 = output_width - h1;
 637        /* phi */
 638        val = (h1 * rsz) - (((input_width >> 1) - o) << 8);
 639        /* skip */
 640        val1 = ((val - 1024) >> 9) << 1;
 641        param->f_div.num_passes = MAX_PASSES;
 642        param->f_div.pass[0].o_hsz = h1 - 1;
 643        param->f_div.pass[0].i_hps = 0;
 644        param->f_div.pass[0].h_phs = 0;
 645        param->f_div.pass[0].src_hps = 0;
 646        param->f_div.pass[0].src_hsz = (input_width >> 2) + o;
 647        param->f_div.pass[1].o_hsz = h2 - 1;
 648        param->f_div.pass[1].i_hps = val1;
 649        param->f_div.pass[1].h_phs = val - (val1 << 8);
 650        param->f_div.pass[1].src_hps = (input_width >> 2) - o;
 651        param->f_div.pass[1].src_hsz = (input_width >> 2) + o;
 652
 653        return 0;
 654}
 655
 656static int
 657resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
 658{
 659        struct vpfe_rsz_config_params *config = &resizer->config.user_config;
 660        struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
 661        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
 662        struct v4l2_mbus_framefmt *outformat1, *outformat2;
 663        struct resizer_params *param = &resizer->config;
 664        struct v4l2_mbus_framefmt *informat;
 665        int decimation;
 666        int line_len_c;
 667        int line_len;
 668        int rsz;
 669        int ret;
 670
 671        informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
 672        outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
 673        outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
 674
 675        decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev);
 676        rsz = vpfe_ipipeif_get_rsz(vpfe_dev);
 677        if (decimation && param->user_config.frame_div_mode_en) {
 678                dev_err(dev,
 679                "dec_en & frame_div_mode_en cannot enabled simultaneously\n");
 680                return -EINVAL;
 681        }
 682
 683        ret = resizer_validate_decimation(dev, decimation, rsz,
 684              param->user_config.frame_div_mode_en, informat->width);
 685        if (ret)
 686                return -EINVAL;
 687
 688        ret = resizer_validate_input_image_format(dev, informat->code,
 689                informat->width, informat->height, &line_len);
 690        if (ret)
 691                return -EINVAL;
 692
 693        if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
 694                param->rsz_en[RSZ_A] = ENABLE;
 695                ret = resizer_validate_output_image_format(dev, outformat1,
 696                                        &line_len, &line_len_c);
 697                if (ret)
 698                        return ret;
 699                param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len;
 700                param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c;
 701                configure_resizer_out_params(resizer, RSZ_A,
 702                                        &param->user_config.output1, 0, 1);
 703
 704                if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12)
 705                        param->rsz_common.raw_flip = 1;
 706                else
 707                        param->rsz_common.raw_flip = 0;
 708
 709                if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
 710                        resizer_enable_422_420_conversion(param,
 711                                                          RSZ_A, ENABLE);
 712                else
 713                        resizer_enable_422_420_conversion(param,
 714                                                          RSZ_A, DISABLE);
 715        }
 716
 717        if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
 718                param->rsz_en[RSZ_B] = ENABLE;
 719                ret = resizer_validate_output_image_format(dev, outformat2,
 720                                &line_len, &line_len_c);
 721                if (ret)
 722                        return ret;
 723                param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
 724                param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
 725                configure_resizer_out_params(resizer, RSZ_B,
 726                                        &param->user_config.output2, 0, 1);
 727                if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
 728                        resizer_enable_422_420_conversion(param,
 729                                                          RSZ_B, ENABLE);
 730                else
 731                        resizer_enable_422_420_conversion(param,
 732                                                          RSZ_B, DISABLE);
 733        }
 734
 735        resizer_configure_common_in_params(resizer);
 736        if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
 737                resizer_calculate_resize_ratios(resizer, RSZ_A);
 738                resizer_calculate_sdram_offsets(resizer, RSZ_A);
 739                /* Overriding resize ratio calculation */
 740                if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
 741                        param->rsz_rsc_param[RSZ_A].v_dif =
 742                                (((informat->height + 1) * 2) * 256) /
 743                                (param->rsz_rsc_param[RSZ_A].o_vsz + 1);
 744                }
 745        }
 746
 747        if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
 748                resizer_calculate_resize_ratios(resizer, RSZ_B);
 749                resizer_calculate_sdram_offsets(resizer, RSZ_B);
 750                /* Overriding resize ratio calculation */
 751                if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
 752                        param->rsz_rsc_param[RSZ_B].v_dif =
 753                                (((informat->height + 1) * 2) * 256) /
 754                                (param->rsz_rsc_param[RSZ_B].o_vsz + 1);
 755                }
 756        }
 757        if (param->user_config.frame_div_mode_en &&
 758                param->rsz_en[RSZ_A]) {
 759                if (!param->rsz_rsc_param[RSZ_A].dscale_en)
 760                        ret = resizer_calculate_normal_f_div_param(dev,
 761                              informat->width,
 762                              param->rsz_rsc_param[RSZ_A].o_vsz + 1,
 763                              &param->rsz_rsc_param[RSZ_A]);
 764                else
 765                        ret = resizer_calculate_down_scale_f_div_param(dev,
 766                              informat->width,
 767                              param->rsz_rsc_param[RSZ_A].o_vsz + 1,
 768                              &param->rsz_rsc_param[RSZ_A]);
 769                if (ret)
 770                        return -EINVAL;
 771        }
 772        if (param->user_config.frame_div_mode_en &&
 773                param->rsz_en[RSZ_B]) {
 774                if (!param->rsz_rsc_param[RSZ_B].dscale_en)
 775                        ret = resizer_calculate_normal_f_div_param(dev,
 776                              informat->width,
 777                              param->rsz_rsc_param[RSZ_B].o_vsz + 1,
 778                              &param->rsz_rsc_param[RSZ_B]);
 779                else
 780                        ret = resizer_calculate_down_scale_f_div_param(dev,
 781                              informat->width,
 782                              param->rsz_rsc_param[RSZ_B].o_vsz + 1,
 783                              &param->rsz_rsc_param[RSZ_B]);
 784                if (ret)
 785                        return -EINVAL;
 786        }
 787        param->rsz_common.passthrough = config->bypass;
 788        if (config->bypass)
 789                resizer_configure_passthru(resizer, 1);
 790        return 0;
 791}
 792
 793static void
 794resizer_set_default_configuration(struct vpfe_resizer_device *resizer)
 795{
 796#define  WIDTH_I 640
 797#define  HEIGHT_I 480
 798#define  WIDTH_O 640
 799#define  HEIGHT_O 480
 800        const struct resizer_params rsz_default_config = {
 801                .oper_mode = RESIZER_MODE_ONE_SHOT,
 802                .rsz_common = {
 803                        .vsz = HEIGHT_I - 1,
 804                        .hsz = WIDTH_I - 1,
 805                        .src_img_fmt = RSZ_IMG_422,
 806                        .raw_flip = 1,  /* flip preserve Raw format */
 807                        .source = IPIPE_DATA,
 808                        .passthrough = BYPASS_OFF,
 809                        .yuv_y_max = 255,
 810                        .yuv_c_max = 255,
 811                        .rsz_seq_crv = DISABLE,
 812                        .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
 813                },
 814                .rsz_rsc_param = {
 815                        {
 816                                .h_flip = DISABLE,
 817                                .v_flip = DISABLE,
 818                                .cen = DISABLE,
 819                                .yen = DISABLE,
 820                                .o_vsz = HEIGHT_O - 1,
 821                                .o_hsz = WIDTH_O - 1,
 822                                .v_dif = 256,
 823                                .v_typ_y = VPFE_RSZ_INTP_CUBIC,
 824                                .v_typ_c = VPFE_RSZ_INTP_CUBIC,
 825                                .h_dif = 256,
 826                                .h_typ_y = VPFE_RSZ_INTP_CUBIC,
 827                                .h_typ_c = VPFE_RSZ_INTP_CUBIC,
 828                                .h_dscale_ave_sz =
 829                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 830                                .v_dscale_ave_sz =
 831                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 832                        },
 833                        {
 834                                .h_flip = DISABLE,
 835                                .v_flip = DISABLE,
 836                                .cen = DISABLE,
 837                                .yen = DISABLE,
 838                                .o_vsz = HEIGHT_O - 1,
 839                                .o_hsz = WIDTH_O - 1,
 840                                .v_dif = 256,
 841                                .v_typ_y = VPFE_RSZ_INTP_CUBIC,
 842                                .v_typ_c = VPFE_RSZ_INTP_CUBIC,
 843                                .h_dif = 256,
 844                                .h_typ_y = VPFE_RSZ_INTP_CUBIC,
 845                                .h_typ_c = VPFE_RSZ_INTP_CUBIC,
 846                                .h_dscale_ave_sz =
 847                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 848                                .v_dscale_ave_sz =
 849                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 850                        },
 851                },
 852                .rsz2rgb = {
 853                        {
 854                                .rgb_en = DISABLE
 855                        },
 856                        {
 857                                .rgb_en = DISABLE
 858                        }
 859                },
 860                .ext_mem_param = {
 861                        {
 862                                .rsz_sdr_oft_y = WIDTH_O << 1,
 863                                .rsz_sdr_ptr_e_y = HEIGHT_O,
 864                                .rsz_sdr_oft_c = WIDTH_O,
 865                                .rsz_sdr_ptr_e_c = HEIGHT_O >> 1,
 866                        },
 867                        {
 868                                .rsz_sdr_oft_y = WIDTH_O << 1,
 869                                .rsz_sdr_ptr_e_y = HEIGHT_O,
 870                                .rsz_sdr_oft_c = WIDTH_O,
 871                                .rsz_sdr_ptr_e_c = HEIGHT_O,
 872                        },
 873                },
 874                .rsz_en[0] = ENABLE,
 875                .rsz_en[1] = DISABLE,
 876                .user_config = {
 877                        .output1 = {
 878                                .v_typ_y = VPFE_RSZ_INTP_CUBIC,
 879                                .v_typ_c = VPFE_RSZ_INTP_CUBIC,
 880                                .h_typ_y = VPFE_RSZ_INTP_CUBIC,
 881                                .h_typ_c = VPFE_RSZ_INTP_CUBIC,
 882                                .h_dscale_ave_sz =
 883                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 884                                .v_dscale_ave_sz =
 885                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 886                        },
 887                        .output2 = {
 888                                .v_typ_y = VPFE_RSZ_INTP_CUBIC,
 889                                .v_typ_c = VPFE_RSZ_INTP_CUBIC,
 890                                .h_typ_y = VPFE_RSZ_INTP_CUBIC,
 891                                .h_typ_c = VPFE_RSZ_INTP_CUBIC,
 892                                .h_dscale_ave_sz =
 893                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 894                                .v_dscale_ave_sz =
 895                                        VPFE_IPIPE_DWN_SCALE_1_OVER_2,
 896                        },
 897                        .yuv_y_max = 255,
 898                        .yuv_c_max = 255,
 899                        .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
 900                },
 901        };
 902        memcpy(&resizer->config, &rsz_default_config,
 903               sizeof(struct resizer_params));
 904}
 905
 906/*
 907 * resizer_set_configuration() - set resizer config
 908 * @resizer: vpfe resizer device pointer.
 909 * @chan_config: resizer channel configuration.
 910 */
 911static int
 912resizer_set_configuration(struct vpfe_resizer_device *resizer,
 913                          struct vpfe_rsz_config *chan_config)
 914{
 915        if (!chan_config->config)
 916                resizer_set_default_configuration(resizer);
 917        else
 918                if (copy_from_user(&resizer->config.user_config,
 919                                   (void __user *)chan_config->config,
 920                                   sizeof(struct vpfe_rsz_config_params)))
 921                        return -EFAULT;
 922
 923        return 0;
 924}
 925
 926/*
 927 * resizer_get_configuration() - get resizer config
 928 * @resizer: vpfe resizer device pointer.
 929 * @channel: image processor logical channel.
 930 * @chan_config: resizer channel configuration.
 931 */
 932static int
 933resizer_get_configuration(struct vpfe_resizer_device *resizer,
 934                   struct vpfe_rsz_config *chan_config)
 935{
 936        struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
 937
 938        if (!chan_config->config) {
 939                dev_err(dev, "Resizer channel invalid pointer\n");
 940                return -EINVAL;
 941        }
 942
 943        if (copy_to_user((void __user *)chan_config->config,
 944                         (void *)&resizer->config.user_config,
 945                         sizeof(struct vpfe_rsz_config_params))) {
 946                dev_err(dev, "resizer_get_configuration: Error in copy to user\n");
 947                return -EFAULT;
 948        }
 949
 950        return 0;
 951}
 952
 953/*
 954 * VPFE video operations
 955 */
 956
 957/*
 958 * resizer_a_video_out_queue() - RESIZER-A video out queue
 959 * @vpfe_dev: vpfe device pointer.
 960 * @addr: buffer address.
 961 */
 962static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev,
 963                                     unsigned long addr)
 964{
 965        struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
 966
 967        return resizer_set_outaddr(resizer->base_addr,
 968                                      &resizer->config, RSZ_A, addr);
 969}
 970
 971/*
 972 * resizer_b_video_out_queue() - RESIZER-B video out queue
 973 * @vpfe_dev: vpfe device pointer.
 974 * @addr: buffer address.
 975 */
 976static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev,
 977                                     unsigned long addr)
 978{
 979        struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
 980
 981        return resizer_set_outaddr(resizer->base_addr,
 982                                   &resizer->config, RSZ_B, addr);
 983}
 984
 985static const struct vpfe_video_operations resizer_a_video_ops = {
 986        .queue = resizer_a_video_out_queue,
 987};
 988
 989static const struct vpfe_video_operations resizer_b_video_ops = {
 990        .queue = resizer_b_video_out_queue,
 991};
 992
 993static void resizer_enable(struct vpfe_resizer_device *resizer, int en)
 994{
 995        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
 996        u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
 997        unsigned char val;
 998
 999        if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
1000                return;
1001
1002        if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF &&
1003           ipipeif_sink == IPIPEIF_INPUT_MEMORY) {
1004                do {
1005                        val = regr_rsz(resizer->base_addr, RSZ_SRC_EN);
1006                } while (val);
1007
1008                if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
1009                        do {
1010                                val = regr_rsz(resizer->base_addr, RSZ_A);
1011                        } while (val);
1012                }
1013                if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
1014                        do {
1015                                val = regr_rsz(resizer->base_addr, RSZ_B);
1016                        } while (val);
1017                }
1018        }
1019        if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1020                rsz_enable(resizer->base_addr, RSZ_A, en);
1021
1022        if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1023                rsz_enable(resizer->base_addr, RSZ_B, en);
1024}
1025
1026
1027/*
1028 * resizer_ss_isr() - resizer module single-shot buffer scheduling isr
1029 * @resizer: vpfe resizer device pointer.
1030 */
1031static void resizer_ss_isr(struct vpfe_resizer_device *resizer)
1032{
1033        struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1034        struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1035        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1036        struct vpfe_pipeline *pipe = &video_out->pipe;
1037        u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1038        u32 val;
1039
1040        if (ipipeif_sink != IPIPEIF_INPUT_MEMORY)
1041                return;
1042
1043        if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) {
1044                val = vpss_dma_complete_interrupt();
1045                if (val != 0 && val != 2)
1046                        return;
1047        }
1048
1049        if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) {
1050                spin_lock(&video_out->dma_queue_lock);
1051                vpfe_video_process_buffer_complete(video_out);
1052                video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
1053                vpfe_video_schedule_next_buffer(video_out);
1054                spin_unlock(&video_out->dma_queue_lock);
1055        }
1056
1057        /* If resizer B is enabled */
1058        if (pipe->output_num > 1 && resizer->resizer_b.output ==
1059            RESIZER_OUTPUT_MEMORY) {
1060                spin_lock(&video_out2->dma_queue_lock);
1061                vpfe_video_process_buffer_complete(video_out2);
1062                video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
1063                vpfe_video_schedule_next_buffer(video_out2);
1064                spin_unlock(&video_out2->dma_queue_lock);
1065        }
1066
1067        /* start HW if buffers are queued */
1068        if (vpfe_video_is_pipe_ready(pipe) &&
1069            resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) {
1070                resizer_enable(resizer, 1);
1071                vpfe_ipipe_enable(vpfe_dev, 1);
1072                vpfe_ipipeif_enable(vpfe_dev);
1073        }
1074}
1075
1076/*
1077 * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr
1078 * @resizer: vpfe resizer device pointer.
1079 */
1080void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer)
1081{
1082        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1083        struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1084        struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1085        struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe;
1086        enum v4l2_field field;
1087        int fid;
1088
1089        if (!video_out->started)
1090                return;
1091
1092        if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
1093                return;
1094
1095        field = video_out->fmt.fmt.pix.field;
1096        if (field == V4L2_FIELD_NONE) {
1097                /* handle progressive frame capture */
1098                if (video_out->cur_frm != video_out->next_frm) {
1099                        vpfe_video_process_buffer_complete(video_out);
1100                        if (pipe->output_num > 1)
1101                                vpfe_video_process_buffer_complete(video_out2);
1102                }
1103
1104                video_out->skip_frame_count--;
1105                if (!video_out->skip_frame_count) {
1106                        video_out->skip_frame_count =
1107                                video_out->skip_frame_count_init;
1108                        rsz_src_enable(resizer->base_addr, 1);
1109                } else {
1110                        rsz_src_enable(resizer->base_addr, 0);
1111                }
1112                return;
1113        }
1114
1115        /* handle interlaced frame capture */
1116        fid = vpfe_isif_get_fid(vpfe_dev);
1117
1118        /* switch the software maintained field id */
1119        video_out->field_id ^= 1;
1120        if (fid == video_out->field_id) {
1121                /*
1122                 * we are in-sync here,continue.
1123                 * One frame is just being captured. If the
1124                 * next frame is available, release the current
1125                 * frame and move on
1126                 */
1127                if (fid == 0 && video_out->cur_frm != video_out->next_frm) {
1128                        vpfe_video_process_buffer_complete(video_out);
1129                        if (pipe->output_num > 1)
1130                                vpfe_video_process_buffer_complete(video_out2);
1131                }
1132        } else if (fid == 0) {
1133                /*
1134                 * out of sync. Recover from any hardware out-of-sync.
1135                 * May loose one frame
1136                 */
1137                video_out->field_id = fid;
1138        }
1139}
1140
1141/*
1142 * vpfe_resizer_dma_isr() - resizer module dma isr
1143 * @resizer: vpfe resizer device pointer.
1144 */
1145void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer)
1146{
1147        struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1148        struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1149        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1150        struct vpfe_pipeline *pipe = &video_out->pipe;
1151        int schedule_capture = 0;
1152        enum v4l2_field field;
1153        int fid;
1154
1155        if (!video_out->started)
1156                return;
1157
1158        if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) {
1159                resizer_ss_isr(resizer);
1160                return;
1161        }
1162
1163        field = video_out->fmt.fmt.pix.field;
1164        if (field == V4L2_FIELD_NONE) {
1165                if (!list_empty(&video_out->dma_queue) &&
1166                        video_out->cur_frm == video_out->next_frm)
1167                        schedule_capture = 1;
1168        } else {
1169                fid = vpfe_isif_get_fid(vpfe_dev);
1170                if (fid == video_out->field_id) {
1171                        /* we are in-sync here,continue */
1172                        if (fid == 1 && !list_empty(&video_out->dma_queue) &&
1173                            video_out->cur_frm == video_out->next_frm)
1174                                schedule_capture = 1;
1175                }
1176        }
1177
1178        if (!schedule_capture)
1179                return;
1180
1181        spin_lock(&video_out->dma_queue_lock);
1182        vpfe_video_schedule_next_buffer(video_out);
1183        spin_unlock(&video_out->dma_queue_lock);
1184        if (pipe->output_num > 1) {
1185                spin_lock(&video_out2->dma_queue_lock);
1186                vpfe_video_schedule_next_buffer(video_out2);
1187                spin_unlock(&video_out2->dma_queue_lock);
1188        }
1189}
1190
1191/*
1192 * V4L2 subdev operations
1193 */
1194
1195/*
1196 * resizer_ioctl() - Handle resizer module private ioctl's
1197 * @sd: pointer to v4l2 subdev structure
1198 * @cmd: configuration command
1199 * @arg: configuration argument
1200 */
1201static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1202{
1203        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1204        struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
1205        struct vpfe_rsz_config *user_config;
1206        int ret = -ENOIOCTLCMD;
1207
1208        if (&resizer->crop_resizer.subdev != sd)
1209                return ret;
1210
1211        switch (cmd) {
1212        case VIDIOC_VPFE_RSZ_S_CONFIG:
1213                user_config = arg;
1214                ret = resizer_set_configuration(resizer, user_config);
1215                break;
1216
1217        case VIDIOC_VPFE_RSZ_G_CONFIG:
1218                user_config = arg;
1219                if (!user_config->config) {
1220                        dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n");
1221                        return -EINVAL;
1222                }
1223                ret = resizer_get_configuration(resizer, user_config);
1224                break;
1225        }
1226        return ret;
1227}
1228
1229static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer)
1230{
1231        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1232        u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1233        u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1234        struct resizer_params *param = &resizer->config;
1235        int ret = 0;
1236
1237        if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY ||
1238            resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) {
1239                if (ipipeif_sink == IPIPEIF_INPUT_MEMORY &&
1240                    ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1241                        ret = resizer_configure_in_single_shot_mode(resizer);
1242                else
1243                        ret =  resizer_configure_in_continuous_mode(resizer);
1244                if (ret)
1245                        return ret;
1246                ret = config_rsz_hw(resizer, param);
1247        }
1248        return ret;
1249}
1250
1251/*
1252 * resizer_set_stream() - Enable/Disable streaming on resizer subdev
1253 * @sd: pointer to v4l2 subdev structure
1254 * @enable: 1 == Enable, 0 == Disable
1255 */
1256static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1257{
1258        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1259
1260        if (&resizer->crop_resizer.subdev != sd)
1261                return 0;
1262
1263        if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY)
1264                return 0;
1265
1266        switch (enable) {
1267        case 1:
1268                if (resizer_do_hw_setup(resizer) < 0)
1269                        return -EINVAL;
1270                resizer_enable(resizer, enable);
1271                break;
1272
1273        case 0:
1274                resizer_enable(resizer, enable);
1275                break;
1276        }
1277
1278        return 0;
1279}
1280
1281/*
1282 * __resizer_get_format() - helper function for getting resizer format
1283 * @sd: pointer to subdev.
1284 * @cfg: V4L2 subdev pad config
1285 * @pad: pad number.
1286 * @which: wanted subdev format.
1287 * Return wanted mbus frame format.
1288 */
1289static struct v4l2_mbus_framefmt *
1290__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1291                     unsigned int pad, enum v4l2_subdev_format_whence which)
1292{
1293        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1294
1295        if (which == V4L2_SUBDEV_FORMAT_TRY)
1296                return v4l2_subdev_get_try_format(sd, cfg, pad);
1297        if (&resizer->crop_resizer.subdev == sd)
1298                return &resizer->crop_resizer.formats[pad];
1299        if (&resizer->resizer_a.subdev == sd)
1300                return &resizer->resizer_a.formats[pad];
1301        if (&resizer->resizer_b.subdev == sd)
1302                return &resizer->resizer_b.formats[pad];
1303        return NULL;
1304}
1305
1306/*
1307 * resizer_try_format() - Handle try format by pad subdev method
1308 * @sd: pointer to subdev.
1309 * @cfg: V4L2 subdev pad config
1310 * @pad: pad num.
1311 * @fmt: pointer to v4l2 format structure.
1312 * @which: wanted subdev format.
1313 */
1314static void
1315resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1316        unsigned int pad, struct v4l2_mbus_framefmt *fmt,
1317        enum v4l2_subdev_format_whence which)
1318{
1319        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1320        unsigned int max_out_height;
1321        unsigned int max_out_width;
1322        unsigned int i;
1323
1324        if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) ||
1325            (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) ||
1326            (&resizer->crop_resizer.subdev == sd &&
1327            (pad == RESIZER_CROP_PAD_SOURCE ||
1328            pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) {
1329                for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) {
1330                        if (fmt->code == resizer_input_formats[i])
1331                                break;
1332                }
1333                /* If not found, use UYVY as default */
1334                if (i >= ARRAY_SIZE(resizer_input_formats))
1335                        fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1336
1337                fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1338                                        MAX_IN_WIDTH);
1339                fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1340                                MAX_IN_HEIGHT);
1341        } else if (&resizer->resizer_a.subdev == sd &&
1342                   pad == RESIZER_PAD_SOURCE) {
1343                max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
1344                max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1345
1346                for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
1347                        if (fmt->code == resizer_output_formats[i])
1348                                break;
1349                }
1350                /* If not found, use UYVY as default */
1351                if (i >= ARRAY_SIZE(resizer_output_formats))
1352                        fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1353
1354                fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
1355                                        max_out_width);
1356                fmt->width &= ~15;
1357                fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
1358                                max_out_height);
1359        } else if (&resizer->resizer_b.subdev == sd &&
1360                   pad == RESIZER_PAD_SOURCE) {
1361                max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B;
1362                max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1363
1364                for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
1365                        if (fmt->code == resizer_output_formats[i])
1366                                break;
1367                }
1368                /* If not found, use UYVY as default */
1369                if (i >= ARRAY_SIZE(resizer_output_formats))
1370                        fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1371
1372                fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
1373                                        max_out_width);
1374                fmt->width &= ~15;
1375                fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
1376                                max_out_height);
1377        }
1378}
1379
1380/*
1381 * resizer_set_format() - Handle set format by pads subdev method
1382 * @sd: pointer to v4l2 subdev structure
1383 * @cfg: V4L2 subdev pad config
1384 * @fmt: pointer to v4l2 subdev format structure
1385 * return -EINVAL or zero on success
1386 */
1387static int resizer_set_format(struct v4l2_subdev *sd,
1388                              struct v4l2_subdev_pad_config *cfg,
1389                              struct v4l2_subdev_format *fmt)
1390{
1391        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1392        struct v4l2_mbus_framefmt *format;
1393
1394        format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which);
1395        if (format == NULL)
1396                return -EINVAL;
1397
1398        resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which);
1399        *format = fmt->format;
1400
1401        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1402                return 0;
1403
1404        if (&resizer->crop_resizer.subdev == sd) {
1405                if (fmt->pad == RESIZER_CROP_PAD_SINK) {
1406                        resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1407                } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE &&
1408                                resizer->crop_resizer.output == RESIZER_A) {
1409                        resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1410                        resizer->crop_resizer.
1411                        formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format;
1412                } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 &&
1413                        resizer->crop_resizer.output2 == RESIZER_B) {
1414                        resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1415                        resizer->crop_resizer.
1416                        formats[RESIZER_CROP_PAD_SOURCE] = fmt->format;
1417                } else {
1418                        return -EINVAL;
1419                }
1420        } else if (&resizer->resizer_a.subdev == sd) {
1421                if (fmt->pad == RESIZER_PAD_SINK)
1422                        resizer->resizer_a.formats[fmt->pad] = fmt->format;
1423                else if (fmt->pad == RESIZER_PAD_SOURCE)
1424                        resizer->resizer_a.formats[fmt->pad] = fmt->format;
1425                else
1426                        return -EINVAL;
1427        } else if (&resizer->resizer_b.subdev == sd) {
1428                if (fmt->pad == RESIZER_PAD_SINK)
1429                        resizer->resizer_b.formats[fmt->pad] = fmt->format;
1430                else if (fmt->pad == RESIZER_PAD_SOURCE)
1431                        resizer->resizer_b.formats[fmt->pad] = fmt->format;
1432                else
1433                        return -EINVAL;
1434        } else {
1435                return -EINVAL;
1436        }
1437
1438        return 0;
1439}
1440
1441/*
1442 * resizer_get_format() - Retrieve the video format on a pad
1443 * @sd: pointer to v4l2 subdev structure.
1444 * @cfg: V4L2 subdev pad config
1445 * @fmt: pointer to v4l2 subdev format structure
1446 * return -EINVAL or zero on success
1447 */
1448static int resizer_get_format(struct v4l2_subdev *sd,
1449                              struct v4l2_subdev_pad_config *cfg,
1450                              struct v4l2_subdev_format *fmt)
1451{
1452        struct v4l2_mbus_framefmt *format;
1453
1454        format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which);
1455        if (format == NULL)
1456                return -EINVAL;
1457
1458        fmt->format = *format;
1459
1460        return 0;
1461}
1462
1463/*
1464 * resizer_enum_frame_size() - enum frame sizes on pads
1465 * @sd: Pointer to subdevice.
1466 * @cfg: V4L2 subdev pad config
1467 * @code: pointer to v4l2_subdev_frame_size_enum structure.
1468 */
1469static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1470                                   struct v4l2_subdev_pad_config *cfg,
1471                                   struct v4l2_subdev_frame_size_enum *fse)
1472{
1473        struct v4l2_mbus_framefmt format;
1474
1475        if (fse->index != 0)
1476                return -EINVAL;
1477
1478        format.code = fse->code;
1479        format.width = 1;
1480        format.height = 1;
1481        resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
1482        fse->min_width = format.width;
1483        fse->min_height = format.height;
1484
1485        if (format.code != fse->code)
1486                return -EINVAL;
1487
1488        format.code = fse->code;
1489        format.width = -1;
1490        format.height = -1;
1491        resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
1492        fse->max_width = format.width;
1493        fse->max_height = format.height;
1494
1495        return 0;
1496}
1497
1498/*
1499 * resizer_enum_mbus_code() - enum mbus codes for pads
1500 * @sd: Pointer to subdevice.
1501 * @cfg: V4L2 subdev pad config
1502 * @code: pointer to v4l2_subdev_mbus_code_enum structure
1503 */
1504static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1505                                  struct v4l2_subdev_pad_config *cfg,
1506                                  struct v4l2_subdev_mbus_code_enum *code)
1507{
1508        if (code->pad == RESIZER_PAD_SINK) {
1509                if (code->index >= ARRAY_SIZE(resizer_input_formats))
1510                        return -EINVAL;
1511
1512                code->code = resizer_input_formats[code->index];
1513        } else if (code->pad == RESIZER_PAD_SOURCE) {
1514                if (code->index >= ARRAY_SIZE(resizer_output_formats))
1515                        return -EINVAL;
1516
1517                code->code = resizer_output_formats[code->index];
1518        }
1519
1520        return 0;
1521}
1522
1523/*
1524 * resizer_init_formats() - Initialize formats on all pads
1525 * @sd: Pointer to subdevice.
1526 * @fh: V4L2 subdev file handle.
1527 *
1528 * Initialize all pad formats with default values. Try formats are
1529 * initialized on the file handle.
1530 */
1531static int resizer_init_formats(struct v4l2_subdev *sd,
1532                                struct v4l2_subdev_fh *fh)
1533{
1534        __u32 which = V4L2_SUBDEV_FORMAT_TRY;
1535        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1536        struct v4l2_subdev_format format;
1537
1538        if (&resizer->crop_resizer.subdev == sd) {
1539                memset(&format, 0, sizeof(format));
1540                format.pad = RESIZER_CROP_PAD_SINK;
1541                format.which = which;
1542                format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1543                format.format.width = MAX_IN_WIDTH;
1544                format.format.height = MAX_IN_HEIGHT;
1545                resizer_set_format(sd, fh->pad, &format);
1546
1547                memset(&format, 0, sizeof(format));
1548                format.pad = RESIZER_CROP_PAD_SOURCE;
1549                format.which = which;
1550                format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1551                format.format.width = MAX_IN_WIDTH;
1552                format.format.height = MAX_IN_WIDTH;
1553                resizer_set_format(sd, fh->pad, &format);
1554
1555                memset(&format, 0, sizeof(format));
1556                format.pad = RESIZER_CROP_PAD_SOURCE2;
1557                format.which = which;
1558                format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1559                format.format.width = MAX_IN_WIDTH;
1560                format.format.height = MAX_IN_WIDTH;
1561                resizer_set_format(sd, fh->pad, &format);
1562        } else if (&resizer->resizer_a.subdev == sd) {
1563                memset(&format, 0, sizeof(format));
1564                format.pad = RESIZER_PAD_SINK;
1565                format.which = which;
1566                format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1567                format.format.width = MAX_IN_WIDTH;
1568                format.format.height = MAX_IN_HEIGHT;
1569                resizer_set_format(sd, fh->pad, &format);
1570
1571                memset(&format, 0, sizeof(format));
1572                format.pad = RESIZER_PAD_SOURCE;
1573                format.which = which;
1574                format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1575                format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
1576                format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1577                resizer_set_format(sd, fh->pad, &format);
1578        } else if (&resizer->resizer_b.subdev == sd) {
1579                memset(&format, 0, sizeof(format));
1580                format.pad = RESIZER_PAD_SINK;
1581                format.which = which;
1582                format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1583                format.format.width = MAX_IN_WIDTH;
1584                format.format.height = MAX_IN_HEIGHT;
1585                resizer_set_format(sd, fh->pad, &format);
1586
1587                memset(&format, 0, sizeof(format));
1588                format.pad = RESIZER_PAD_SOURCE;
1589                format.which = which;
1590                format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1591                format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B;
1592                format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1593                resizer_set_format(sd, fh->pad, &format);
1594        }
1595
1596        return 0;
1597}
1598
1599/* subdev core operations */
1600static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
1601        .ioctl = resizer_ioctl,
1602};
1603
1604/* subdev internal operations */
1605static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1606        .open = resizer_init_formats,
1607};
1608
1609/* subdev video operations */
1610static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1611        .s_stream = resizer_set_stream,
1612};
1613
1614/* subdev pad operations */
1615static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1616        .enum_mbus_code = resizer_enum_mbus_code,
1617        .enum_frame_size = resizer_enum_frame_size,
1618        .get_fmt = resizer_get_format,
1619        .set_fmt = resizer_set_format,
1620};
1621
1622/* subdev operations */
1623static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1624        .core = &resizer_v4l2_core_ops,
1625        .video = &resizer_v4l2_video_ops,
1626        .pad = &resizer_v4l2_pad_ops,
1627};
1628
1629/*
1630 * Media entity operations
1631 */
1632
1633/*
1634 * resizer_link_setup() - Setup resizer connections
1635 * @entity: Pointer to media entity structure
1636 * @local: Pointer to local pad array
1637 * @remote: Pointer to remote pad array
1638 * @flags: Link flags
1639 * return -EINVAL or zero on success
1640 */
1641static int resizer_link_setup(struct media_entity *entity,
1642                           const struct media_pad *local,
1643                           const struct media_pad *remote, u32 flags)
1644{
1645        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1646        struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1647        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1648        u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1649        u16 ipipe_source = vpfe_dev->vpfe_ipipe.output;
1650        unsigned int index = local->index;
1651
1652        /* FIXME: this is actually a hack! */
1653        if (is_media_entity_v4l2_subdev(remote->entity))
1654                index |= 2 << 16;
1655
1656        if (&resizer->crop_resizer.subdev == sd) {
1657                switch (index) {
1658                case RESIZER_CROP_PAD_SINK | 2 << 16:
1659                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1660                                resizer->crop_resizer.input =
1661                                        RESIZER_CROP_INPUT_NONE;
1662                                break;
1663                        }
1664
1665                        if (resizer->crop_resizer.input !=
1666                           RESIZER_CROP_INPUT_NONE)
1667                                return -EBUSY;
1668                        if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1669                                resizer->crop_resizer.input =
1670                                                RESIZER_CROP_INPUT_IPIPEIF;
1671                        else if (ipipe_source == IPIPE_OUTPUT_RESIZER)
1672                                resizer->crop_resizer.input =
1673                                                RESIZER_CROP_INPUT_IPIPE;
1674                        else
1675                                return -EINVAL;
1676                        break;
1677
1678                case RESIZER_CROP_PAD_SOURCE | 2 << 16:
1679                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1680                                resizer->crop_resizer.output =
1681                                RESIZER_CROP_OUTPUT_NONE;
1682                                break;
1683                        }
1684                        if (resizer->crop_resizer.output !=
1685                            RESIZER_CROP_OUTPUT_NONE)
1686                                return -EBUSY;
1687                        resizer->crop_resizer.output = RESIZER_A;
1688                        break;
1689
1690                case RESIZER_CROP_PAD_SOURCE2 | 2 << 16:
1691                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1692                                resizer->crop_resizer.output2 =
1693                                        RESIZER_CROP_OUTPUT_NONE;
1694                                break;
1695                        }
1696                        if (resizer->crop_resizer.output2 !=
1697                            RESIZER_CROP_OUTPUT_NONE)
1698                                return -EBUSY;
1699                        resizer->crop_resizer.output2 = RESIZER_B;
1700                        break;
1701
1702                default:
1703                        return -EINVAL;
1704                }
1705        } else if (&resizer->resizer_a.subdev == sd) {
1706                switch (index) {
1707                case RESIZER_PAD_SINK | 2 << 16:
1708                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1709                                resizer->resizer_a.input = RESIZER_INPUT_NONE;
1710                                break;
1711                        }
1712                        if (resizer->resizer_a.input != RESIZER_INPUT_NONE)
1713                                return -EBUSY;
1714                        resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER;
1715                        break;
1716
1717                case RESIZER_PAD_SOURCE:
1718                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1719                                resizer->resizer_a.output = RESIZER_OUTPUT_NONE;
1720                                break;
1721                        }
1722                        if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1723                                return -EBUSY;
1724                        resizer->resizer_a.output = RESIZER_OUTPUT_MEMORY;
1725                        break;
1726
1727                default:
1728                        return -EINVAL;
1729                }
1730        } else if (&resizer->resizer_b.subdev == sd) {
1731                switch (index) {
1732                case RESIZER_PAD_SINK | 2 << 16:
1733                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1734                                resizer->resizer_b.input = RESIZER_INPUT_NONE;
1735                                break;
1736                        }
1737                        if (resizer->resizer_b.input != RESIZER_INPUT_NONE)
1738                                return -EBUSY;
1739                        resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER;
1740                        break;
1741
1742                case RESIZER_PAD_SOURCE:
1743                        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1744                                resizer->resizer_b.output = RESIZER_OUTPUT_NONE;
1745                                break;
1746                        }
1747                        if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1748                                return -EBUSY;
1749                        resizer->resizer_b.output = RESIZER_OUTPUT_MEMORY;
1750                        break;
1751
1752                default:
1753                        return -EINVAL;
1754                }
1755        } else {
1756                return -EINVAL;
1757        }
1758
1759        return 0;
1760}
1761
1762static const struct media_entity_operations resizer_media_ops = {
1763        .link_setup = resizer_link_setup,
1764};
1765
1766/*
1767 * vpfe_resizer_unregister_entities() - Unregister entity
1768 * @vpfe_rsz - pointer to resizer subdevice structure.
1769 */
1770void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
1771{
1772        /* unregister video devices */
1773        vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
1774        vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
1775
1776        /* unregister subdev */
1777        v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
1778        v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
1779        v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
1780        /* cleanup entity */
1781        media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
1782        media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
1783        media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
1784}
1785
1786/*
1787 * vpfe_resizer_register_entities() - Register entity
1788 * @resizer - pointer to resizer device.
1789 * @vdev: pointer to v4l2 device structure.
1790 */
1791int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
1792                                   struct v4l2_device *vdev)
1793{
1794        struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1795        unsigned int flags = 0;
1796        int ret;
1797
1798        /* Register the crop resizer subdev */
1799        ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev);
1800        if (ret < 0) {
1801                pr_err("Failed to register crop resizer as v4l2-subdev\n");
1802                return ret;
1803        }
1804        /* Register Resizer-A subdev */
1805        ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev);
1806        if (ret < 0) {
1807                pr_err("Failed to register resizer-a as v4l2-subdev\n");
1808                return ret;
1809        }
1810        /* Register Resizer-B subdev */
1811        ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev);
1812        if (ret < 0) {
1813                pr_err("Failed to register resizer-b as v4l2-subdev\n");
1814                return ret;
1815        }
1816        /* Register video-out device for resizer-a */
1817        ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev);
1818        if (ret) {
1819                pr_err("Failed to register RSZ-A video-out device\n");
1820                goto out_video_out2_register;
1821        }
1822        resizer->resizer_a.video_out.vpfe_dev = vpfe_dev;
1823
1824        /* Register video-out device for resizer-b */
1825        ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev);
1826        if (ret) {
1827                pr_err("Failed to register RSZ-B video-out device\n");
1828                goto out_video_out2_register;
1829        }
1830        resizer->resizer_b.video_out.vpfe_dev = vpfe_dev;
1831
1832        /* create link between Resizer Crop----> Resizer A*/
1833        ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 1,
1834                                &resizer->resizer_a.subdev.entity,
1835                                0, flags);
1836        if (ret < 0)
1837                goto out_create_link;
1838
1839        /* create link between Resizer Crop----> Resizer B*/
1840        ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 2,
1841                                &resizer->resizer_b.subdev.entity,
1842                                0, flags);
1843        if (ret < 0)
1844                goto out_create_link;
1845
1846        /* create link between Resizer A ----> video out */
1847        ret = media_create_pad_link(&resizer->resizer_a.subdev.entity, 1,
1848                &resizer->resizer_a.video_out.video_dev.entity, 0, flags);
1849        if (ret < 0)
1850                goto out_create_link;
1851
1852        /* create link between Resizer B ----> video out */
1853        ret = media_create_pad_link(&resizer->resizer_b.subdev.entity, 1,
1854                &resizer->resizer_b.video_out.video_dev.entity, 0, flags);
1855        if (ret < 0)
1856                goto out_create_link;
1857
1858        return 0;
1859
1860out_create_link:
1861        vpfe_video_unregister(&resizer->resizer_b.video_out);
1862out_video_out2_register:
1863        vpfe_video_unregister(&resizer->resizer_a.video_out);
1864        v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
1865        v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
1866        v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
1867        media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
1868        media_entity_cleanup(&resizer->resizer_a.subdev.entity);
1869        media_entity_cleanup(&resizer->resizer_b.subdev.entity);
1870        return ret;
1871}
1872
1873/*
1874 * vpfe_resizer_init() - resizer device initialization.
1875 * @vpfe_rsz - pointer to resizer device
1876 * @pdev: platform device pointer.
1877 */
1878int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
1879                      struct platform_device *pdev)
1880{
1881        struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev;
1882        struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0];
1883        struct media_entity *me = &sd->entity;
1884        resource_size_t res_len;
1885        struct resource *res;
1886        int ret;
1887
1888        res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1889        if (!res)
1890                return -ENOENT;
1891
1892        res_len = resource_size(res);
1893        res = request_mem_region(res->start, res_len, res->name);
1894        if (!res)
1895                return -EBUSY;
1896
1897        vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len);
1898        if (!vpfe_rsz->base_addr)
1899                return -EBUSY;
1900
1901        v4l2_subdev_init(sd, &resizer_v4l2_ops);
1902        sd->internal_ops = &resizer_v4l2_internal_ops;
1903        strscpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
1904        sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1905        v4l2_set_subdevdata(sd, vpfe_rsz);
1906        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1907
1908        pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1909        pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1910        pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE;
1911
1912        vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE;
1913        vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE;
1914        vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE;
1915        vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz;
1916        me->ops = &resizer_media_ops;
1917        ret = media_entity_pads_init(me, RESIZER_CROP_PADS_NUM, pads);
1918        if (ret)
1919                return ret;
1920
1921        sd = &vpfe_rsz->resizer_a.subdev;
1922        pads = &vpfe_rsz->resizer_a.pads[0];
1923        me = &sd->entity;
1924
1925        v4l2_subdev_init(sd, &resizer_v4l2_ops);
1926        sd->internal_ops = &resizer_v4l2_internal_ops;
1927        strscpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
1928        sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1929        v4l2_set_subdevdata(sd, vpfe_rsz);
1930        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1931
1932        pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1933        pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1934
1935        vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE;
1936        vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE;
1937        vpfe_rsz->resizer_a.rsz_device = vpfe_rsz;
1938        me->ops = &resizer_media_ops;
1939        ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
1940        if (ret)
1941                return ret;
1942
1943        sd = &vpfe_rsz->resizer_b.subdev;
1944        pads = &vpfe_rsz->resizer_b.pads[0];
1945        me = &sd->entity;
1946
1947        v4l2_subdev_init(sd, &resizer_v4l2_ops);
1948        sd->internal_ops = &resizer_v4l2_internal_ops;
1949        strscpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
1950        sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1951        v4l2_set_subdevdata(sd, vpfe_rsz);
1952        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1953
1954        pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1955        pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1956
1957        vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE;
1958        vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE;
1959        vpfe_rsz->resizer_b.rsz_device = vpfe_rsz;
1960        me->ops = &resizer_media_ops;
1961        ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads);
1962        if (ret)
1963                return ret;
1964
1965        vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops;
1966        vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1967        ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A");
1968        if (ret) {
1969                pr_err("Failed to init RSZ video-out device\n");
1970                return ret;
1971        }
1972        vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops;
1973        vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1974        ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B");
1975        if (ret) {
1976                pr_err("Failed to init RSZ video-out2 device\n");
1977                return ret;
1978        }
1979        memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params));
1980
1981        return 0;
1982}
1983
1984void
1985vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
1986                     struct platform_device *pdev)
1987{
1988        struct resource *res;
1989
1990        iounmap(vpfe_rsz->base_addr);
1991        res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1992        if (res)
1993                release_mem_region(res->start,
1994                                        resource_size(res));
1995}
1996