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