linux/drivers/media/video/omap3isp/ispresizer.c
<<
>>
Prefs
   1/*
   2 * ispresizer.c
   3 *
   4 * TI OMAP3 ISP - Resizer module
   5 *
   6 * Copyright (C) 2010 Nokia Corporation
   7 * Copyright (C) 2009 Texas Instruments, Inc
   8 *
   9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  10 *           Sakari Ailus <sakari.ailus@iki.fi>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 *
  16 * This program is distributed in the hope that it will be useful, but
  17 * WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  24 * 02110-1301 USA
  25 */
  26
  27#include <linux/device.h>
  28#include <linux/mm.h>
  29#include <linux/module.h>
  30
  31#include "isp.h"
  32#include "ispreg.h"
  33#include "ispresizer.h"
  34
  35/*
  36 * Resizer Constants
  37 */
  38#define MIN_RESIZE_VALUE                64
  39#define MID_RESIZE_VALUE                512
  40#define MAX_RESIZE_VALUE                1024
  41
  42#define MIN_IN_WIDTH                    32
  43#define MIN_IN_HEIGHT                   32
  44#define MAX_IN_WIDTH_MEMORY_MODE        4095
  45#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1  1280
  46#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2  4095
  47#define MAX_IN_HEIGHT                   4095
  48
  49#define MIN_OUT_WIDTH                   16
  50#define MIN_OUT_HEIGHT                  2
  51#define MAX_OUT_HEIGHT                  4095
  52
  53/*
  54 * Resizer Use Constraints
  55 * "TRM ES3.1, table 12-46"
  56 */
  57#define MAX_4TAP_OUT_WIDTH_ES1          1280
  58#define MAX_7TAP_OUT_WIDTH_ES1          640
  59#define MAX_4TAP_OUT_WIDTH_ES2          3312
  60#define MAX_7TAP_OUT_WIDTH_ES2          1650
  61#define MAX_4TAP_OUT_WIDTH_3630         4096
  62#define MAX_7TAP_OUT_WIDTH_3630         2048
  63
  64/*
  65 * Constants for ratio calculation
  66 */
  67#define RESIZE_DIVISOR                  256
  68#define DEFAULT_PHASE                   1
  69
  70/*
  71 * Default (and only) configuration of filter coefficients.
  72 * 7-tap mode is for scale factors 0.25x to 0.5x.
  73 * 4-tap mode is for scale factors 0.5x to 4.0x.
  74 * There shouldn't be any reason to recalculate these, EVER.
  75 */
  76static const struct isprsz_coef filter_coefs = {
  77        /* For 8-phase 4-tap horizontal filter: */
  78        {
  79                0x0000, 0x0100, 0x0000, 0x0000,
  80                0x03FA, 0x00F6, 0x0010, 0x0000,
  81                0x03F9, 0x00DB, 0x002C, 0x0000,
  82                0x03FB, 0x00B3, 0x0053, 0x03FF,
  83                0x03FD, 0x0082, 0x0084, 0x03FD,
  84                0x03FF, 0x0053, 0x00B3, 0x03FB,
  85                0x0000, 0x002C, 0x00DB, 0x03F9,
  86                0x0000, 0x0010, 0x00F6, 0x03FA
  87        },
  88        /* For 8-phase 4-tap vertical filter: */
  89        {
  90                0x0000, 0x0100, 0x0000, 0x0000,
  91                0x03FA, 0x00F6, 0x0010, 0x0000,
  92                0x03F9, 0x00DB, 0x002C, 0x0000,
  93                0x03FB, 0x00B3, 0x0053, 0x03FF,
  94                0x03FD, 0x0082, 0x0084, 0x03FD,
  95                0x03FF, 0x0053, 0x00B3, 0x03FB,
  96                0x0000, 0x002C, 0x00DB, 0x03F9,
  97                0x0000, 0x0010, 0x00F6, 0x03FA
  98        },
  99        /* For 4-phase 7-tap horizontal filter: */
 100        #define DUMMY 0
 101        {
 102                0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
 103                0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
 104                0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
 105                0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
 106        },
 107        /* For 4-phase 7-tap vertical filter: */
 108        {
 109                0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
 110                0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
 111                0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
 112                0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
 113        }
 114        /*
 115         * The dummy padding is required in 7-tap mode because of how the
 116         * registers are arranged physically.
 117         */
 118        #undef DUMMY
 119};
 120
 121/*
 122 * __resizer_get_format - helper function for getting resizer format
 123 * @res   : pointer to resizer private structure
 124 * @pad   : pad number
 125 * @fh    : V4L2 subdev file handle
 126 * @which : wanted subdev format
 127 * return zero
 128 */
 129static struct v4l2_mbus_framefmt *
 130__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
 131                     unsigned int pad, enum v4l2_subdev_format_whence which)
 132{
 133        if (which == V4L2_SUBDEV_FORMAT_TRY)
 134                return v4l2_subdev_get_try_format(fh, pad);
 135        else
 136                return &res->formats[pad];
 137}
 138
 139/*
 140 * __resizer_get_crop - helper function for getting resizer crop rectangle
 141 * @res   : pointer to resizer private structure
 142 * @fh    : V4L2 subdev file handle
 143 * @which : wanted subdev crop rectangle
 144 */
 145static struct v4l2_rect *
 146__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
 147                   enum v4l2_subdev_format_whence which)
 148{
 149        if (which == V4L2_SUBDEV_FORMAT_TRY)
 150                return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
 151        else
 152                return &res->crop.request;
 153}
 154
 155/*
 156 * resizer_set_filters - Set resizer filters
 157 * @res: Device context.
 158 * @h_coeff: horizontal coefficient
 159 * @v_coeff: vertical coefficient
 160 * Return none
 161 */
 162static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
 163                                const u16 *v_coeff)
 164{
 165        struct isp_device *isp = to_isp_device(res);
 166        u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
 167        int i;
 168
 169        startaddr_h = ISPRSZ_HFILT10;
 170        startaddr_v = ISPRSZ_VFILT10;
 171
 172        for (i = 0; i < COEFF_CNT; i += 2) {
 173                tmp_h = h_coeff[i] |
 174                        (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
 175                tmp_v = v_coeff[i] |
 176                        (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
 177                isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
 178                isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
 179                startaddr_h += 4;
 180                startaddr_v += 4;
 181        }
 182}
 183
 184/*
 185 * resizer_set_bilinear - Chrominance horizontal algorithm select
 186 * @res: Device context.
 187 * @type: Filtering interpolation type.
 188 *
 189 * Filtering that is same as luminance processing is
 190 * intended only for downsampling, and bilinear interpolation
 191 * is intended only for upsampling.
 192 */
 193static void resizer_set_bilinear(struct isp_res_device *res,
 194                                 enum resizer_chroma_algo type)
 195{
 196        struct isp_device *isp = to_isp_device(res);
 197
 198        if (type == RSZ_BILINEAR)
 199                isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 200                            ISPRSZ_CNT_CBILIN);
 201        else
 202                isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 203                            ISPRSZ_CNT_CBILIN);
 204}
 205
 206/*
 207 * resizer_set_ycpos - Luminance and chrominance order
 208 * @res: Device context.
 209 * @order: order type.
 210 */
 211static void resizer_set_ycpos(struct isp_res_device *res,
 212                              enum v4l2_mbus_pixelcode pixelcode)
 213{
 214        struct isp_device *isp = to_isp_device(res);
 215
 216        switch (pixelcode) {
 217        case V4L2_MBUS_FMT_YUYV8_1X16:
 218                isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 219                            ISPRSZ_CNT_YCPOS);
 220                break;
 221        case V4L2_MBUS_FMT_UYVY8_1X16:
 222                isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 223                            ISPRSZ_CNT_YCPOS);
 224                break;
 225        default:
 226                return;
 227        }
 228}
 229
 230/*
 231 * resizer_set_phase - Setup horizontal and vertical starting phase
 232 * @res: Device context.
 233 * @h_phase: horizontal phase parameters.
 234 * @v_phase: vertical phase parameters.
 235 *
 236 * Horizontal and vertical phase range is 0 to 7
 237 */
 238static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
 239                              u32 v_phase)
 240{
 241        struct isp_device *isp = to_isp_device(res);
 242        u32 rgval = 0;
 243
 244        rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
 245              ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
 246        rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
 247        rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
 248
 249        isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
 250}
 251
 252/*
 253 * resizer_set_luma - Setup luminance enhancer parameters
 254 * @res: Device context.
 255 * @luma: Structure for luminance enhancer parameters.
 256 *
 257 * Algorithm select:
 258 *  0x0: Disable
 259 *  0x1: [-1  2 -1]/2 high-pass filter
 260 *  0x2: [-1 -2  6 -2 -1]/4 high-pass filter
 261 *
 262 * Maximum gain:
 263 *  The data is coded in U4Q4 representation.
 264 *
 265 * Slope:
 266 *  The data is coded in U4Q4 representation.
 267 *
 268 * Coring offset:
 269 *  The data is coded in U8Q0 representation.
 270 *
 271 * The new luminance value is computed as:
 272 *  Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
 273 */
 274static void resizer_set_luma(struct isp_res_device *res,
 275                             struct resizer_luma_yenh *luma)
 276{
 277        struct isp_device *isp = to_isp_device(res);
 278        u32 rgval = 0;
 279
 280        rgval  = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
 281                  & ISPRSZ_YENH_ALGO_MASK;
 282        rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
 283                  & ISPRSZ_YENH_GAIN_MASK;
 284        rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
 285                  & ISPRSZ_YENH_SLOP_MASK;
 286        rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
 287                  & ISPRSZ_YENH_CORE_MASK;
 288
 289        isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
 290}
 291
 292/*
 293 * resizer_set_source - Input source select
 294 * @res: Device context.
 295 * @source: Input source type
 296 *
 297 * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
 298 * Preview/CCDC engine, otherwise from memory.
 299 */
 300static void resizer_set_source(struct isp_res_device *res,
 301                               enum resizer_input_entity source)
 302{
 303        struct isp_device *isp = to_isp_device(res);
 304
 305        if (source == RESIZER_INPUT_MEMORY)
 306                isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 307                            ISPRSZ_CNT_INPSRC);
 308        else
 309                isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 310                            ISPRSZ_CNT_INPSRC);
 311}
 312
 313/*
 314 * resizer_set_ratio - Setup horizontal and vertical resizing value
 315 * @res: Device context.
 316 * @ratio: Structure for ratio parameters.
 317 *
 318 * Resizing range from 64 to 1024
 319 */
 320static void resizer_set_ratio(struct isp_res_device *res,
 321                              const struct resizer_ratio *ratio)
 322{
 323        struct isp_device *isp = to_isp_device(res);
 324        const u16 *h_filter, *v_filter;
 325        u32 rgval = 0;
 326
 327        rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
 328                              ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
 329        rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
 330                  & ISPRSZ_CNT_HRSZ_MASK;
 331        rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
 332                  & ISPRSZ_CNT_VRSZ_MASK;
 333        isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
 334
 335        /* prepare horizontal filter coefficients */
 336        if (ratio->horz > MID_RESIZE_VALUE)
 337                h_filter = &filter_coefs.h_filter_coef_7tap[0];
 338        else
 339                h_filter = &filter_coefs.h_filter_coef_4tap[0];
 340
 341        /* prepare vertical filter coefficients */
 342        if (ratio->vert > MID_RESIZE_VALUE)
 343                v_filter = &filter_coefs.v_filter_coef_7tap[0];
 344        else
 345                v_filter = &filter_coefs.v_filter_coef_4tap[0];
 346
 347        resizer_set_filters(res, h_filter, v_filter);
 348}
 349
 350/*
 351 * resizer_set_dst_size - Setup the output height and width
 352 * @res: Device context.
 353 * @width: Output width.
 354 * @height: Output height.
 355 *
 356 * Width :
 357 *  The value must be EVEN.
 358 *
 359 * Height:
 360 *  The number of bytes written to SDRAM must be
 361 *  a multiple of 16-bytes if the vertical resizing factor
 362 *  is greater than 1x (upsizing)
 363 */
 364static void resizer_set_output_size(struct isp_res_device *res,
 365                                    u32 width, u32 height)
 366{
 367        struct isp_device *isp = to_isp_device(res);
 368        u32 rgval = 0;
 369
 370        dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
 371        rgval  = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
 372                 & ISPRSZ_OUT_SIZE_HORZ_MASK;
 373        rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
 374                 & ISPRSZ_OUT_SIZE_VERT_MASK;
 375        isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
 376}
 377
 378/*
 379 * resizer_set_output_offset - Setup memory offset for the output lines.
 380 * @res: Device context.
 381 * @offset: Memory offset.
 382 *
 383 * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
 384 * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
 385 * the SDRAM line offset must be set on a 256-byte boundary
 386 */
 387static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
 388{
 389        struct isp_device *isp = to_isp_device(res);
 390
 391        isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
 392}
 393
 394/*
 395 * resizer_set_start - Setup vertical and horizontal start position
 396 * @res: Device context.
 397 * @left: Horizontal start position.
 398 * @top: Vertical start position.
 399 *
 400 * Vertical start line:
 401 *  This field makes sense only when the resizer obtains its input
 402 *  from the preview engine/CCDC
 403 *
 404 * Horizontal start pixel:
 405 *  Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
 406 *  When the resizer gets its input from SDRAM, this field must be set
 407 *  to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
 408 */
 409static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
 410{
 411        struct isp_device *isp = to_isp_device(res);
 412        u32 rgval = 0;
 413
 414        rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
 415                & ISPRSZ_IN_START_HORZ_ST_MASK;
 416        rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
 417                 & ISPRSZ_IN_START_VERT_ST_MASK;
 418
 419        isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
 420}
 421
 422/*
 423 * resizer_set_input_size - Setup the input size
 424 * @res: Device context.
 425 * @width: The range is 0 to 4095 pixels
 426 * @height: The range is 0 to 4095 lines
 427 */
 428static void resizer_set_input_size(struct isp_res_device *res,
 429                                   u32 width, u32 height)
 430{
 431        struct isp_device *isp = to_isp_device(res);
 432        u32 rgval = 0;
 433
 434        dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
 435
 436        rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
 437                & ISPRSZ_IN_SIZE_HORZ_MASK;
 438        rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
 439                 & ISPRSZ_IN_SIZE_VERT_MASK;
 440
 441        isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
 442}
 443
 444/*
 445 * resizer_set_src_offs - Setup the memory offset for the input lines
 446 * @res: Device context.
 447 * @offset: Memory offset.
 448 *
 449 * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
 450 * boundary; the 5 LSBs are read-only. This field must be programmed to be
 451 * 0x0 if the resizer input is from preview engine/CCDC.
 452 */
 453static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
 454{
 455        struct isp_device *isp = to_isp_device(res);
 456
 457        isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
 458}
 459
 460/*
 461 * resizer_set_intype - Input type select
 462 * @res: Device context.
 463 * @type: Pixel format type.
 464 */
 465static void resizer_set_intype(struct isp_res_device *res,
 466                               enum resizer_colors_type type)
 467{
 468        struct isp_device *isp = to_isp_device(res);
 469
 470        if (type == RSZ_COLOR8)
 471                isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 472                            ISPRSZ_CNT_INPTYP);
 473        else
 474                isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
 475                            ISPRSZ_CNT_INPTYP);
 476}
 477
 478/*
 479 * __resizer_set_inaddr - Helper function for set input address
 480 * @res : pointer to resizer private data structure
 481 * @addr: input address
 482 * return none
 483 */
 484static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
 485{
 486        struct isp_device *isp = to_isp_device(res);
 487
 488        isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
 489}
 490
 491/*
 492 * The data rate at the horizontal resizer output must not exceed half the
 493 * functional clock or 100 MP/s, whichever is lower. According to the TRM
 494 * there's no similar requirement for the vertical resizer output. However
 495 * experience showed that vertical upscaling by 4 leads to SBL overflows (with
 496 * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
 497 * output data rate to the functional clock or 200 MP/s, whichever is lower,
 498 * seems to get rid of SBL overflows.
 499 *
 500 * The maximum data rate at the output of the horizontal resizer can thus be
 501 * computed with
 502 *
 503 * max intermediate rate <= L3 clock * input height / output height
 504 * max intermediate rate <= L3 clock / 2
 505 *
 506 * The maximum data rate at the resizer input is then
 507 *
 508 * max input rate <= max intermediate rate * input width / output width
 509 *
 510 * where the input width and height are the resizer input crop rectangle size.
 511 * The TRM doesn't clearly explain if that's a maximum instant data rate or a
 512 * maximum average data rate.
 513 */
 514void omap3isp_resizer_max_rate(struct isp_res_device *res,
 515                               unsigned int *max_rate)
 516{
 517        struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
 518        const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
 519        unsigned long limit = min(pipe->l3_ick, 200000000UL);
 520        unsigned long clock;
 521
 522        clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
 523        clock = min(clock, limit / 2);
 524        *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
 525}
 526
 527/*
 528 * When the resizer processes images from memory, the driver must slow down read
 529 * requests on the input to at least comply with the internal data rate
 530 * requirements. If the application real-time requirements can cope with slower
 531 * processing, the resizer can be slowed down even more to put less pressure on
 532 * the overall system.
 533 *
 534 * When the resizer processes images on the fly (either from the CCDC or the
 535 * preview module), the same data rate requirements apply but they can't be
 536 * enforced at the resizer level. The image input module (sensor, CCP2 or
 537 * preview module) must not provide image data faster than the resizer can
 538 * process.
 539 *
 540 * For live image pipelines, the data rate is set by the frame format, size and
 541 * rate. The sensor output frame rate must not exceed the maximum resizer data
 542 * rate.
 543 *
 544 * The resizer slows down read requests by inserting wait cycles in the SBL
 545 * requests. The maximum number of 256-byte requests per second can be computed
 546 * as (the data rate is multiplied by 2 to convert from pixels per second to
 547 * bytes per second)
 548 *
 549 * request per second = data rate * 2 / 256
 550 * cycles per request = cycles per second / requests per second
 551 *
 552 * The number of cycles per second is controlled by the L3 clock, leading to
 553 *
 554 * cycles per request = L3 frequency / 2 * 256 / data rate
 555 */
 556static void resizer_adjust_bandwidth(struct isp_res_device *res)
 557{
 558        struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
 559        struct isp_device *isp = to_isp_device(res);
 560        unsigned long l3_ick = pipe->l3_ick;
 561        struct v4l2_fract *timeperframe;
 562        unsigned int cycles_per_frame;
 563        unsigned int requests_per_frame;
 564        unsigned int cycles_per_request;
 565        unsigned int granularity;
 566        unsigned int minimum;
 567        unsigned int maximum;
 568        unsigned int value;
 569
 570        if (res->input != RESIZER_INPUT_MEMORY) {
 571                isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
 572                            ISPSBL_SDR_REQ_RSZ_EXP_MASK);
 573                return;
 574        }
 575
 576        switch (isp->revision) {
 577        case ISP_REVISION_1_0:
 578        case ISP_REVISION_2_0:
 579        default:
 580                granularity = 1024;
 581                break;
 582
 583        case ISP_REVISION_15_0:
 584                granularity = 32;
 585                break;
 586        }
 587
 588        /* Compute the minimum number of cycles per request, based on the
 589         * pipeline maximum data rate. This is an absolute lower bound if we
 590         * don't want SBL overflows, so round the value up.
 591         */
 592        cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
 593                                     pipe->max_rate);
 594        minimum = DIV_ROUND_UP(cycles_per_request, granularity);
 595
 596        /* Compute the maximum number of cycles per request, based on the
 597         * requested frame rate. This is a soft upper bound to achieve a frame
 598         * rate equal or higher than the requested value, so round the value
 599         * down.
 600         */
 601        timeperframe = &pipe->max_timeperframe;
 602
 603        requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
 604                           * res->crop.active.height;
 605        cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
 606                                   timeperframe->denominator);
 607        cycles_per_request = cycles_per_frame / requests_per_frame;
 608
 609        maximum = cycles_per_request / granularity;
 610
 611        value = max(minimum, maximum);
 612
 613        dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
 614        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
 615                        ISPSBL_SDR_REQ_RSZ_EXP_MASK,
 616                        value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
 617}
 618
 619/*
 620 * omap3isp_resizer_busy - Checks if ISP resizer is busy.
 621 *
 622 * Returns busy field from ISPRSZ_PCR register.
 623 */
 624int omap3isp_resizer_busy(struct isp_res_device *res)
 625{
 626        struct isp_device *isp = to_isp_device(res);
 627
 628        return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
 629                             ISPRSZ_PCR_BUSY;
 630}
 631
 632/*
 633 * resizer_set_inaddr - Sets the memory address of the input frame.
 634 * @addr: 32bit memory address aligned on 32byte boundary.
 635 */
 636static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
 637{
 638        res->addr_base = addr;
 639
 640        /* This will handle crop settings in stream off state */
 641        if (res->crop_offset)
 642                addr += res->crop_offset & ~0x1f;
 643
 644        __resizer_set_inaddr(res, addr);
 645}
 646
 647/*
 648 * Configures the memory address to which the output frame is written.
 649 * @addr: 32bit memory address aligned on 32byte boundary.
 650 * Note: For SBL efficiency reasons the address should be on a 256-byte
 651 * boundary.
 652 */
 653static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
 654{
 655        struct isp_device *isp = to_isp_device(res);
 656
 657        /*
 658         * Set output address. This needs to be in its own function
 659         * because it changes often.
 660         */
 661        isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
 662                       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
 663}
 664
 665/*
 666 * resizer_print_status - Prints the values of the resizer module registers.
 667 */
 668#define RSZ_PRINT_REGISTER(isp, name)\
 669        dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
 670                isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
 671
 672static void resizer_print_status(struct isp_res_device *res)
 673{
 674        struct isp_device *isp = to_isp_device(res);
 675
 676        dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
 677
 678        RSZ_PRINT_REGISTER(isp, PCR);
 679        RSZ_PRINT_REGISTER(isp, CNT);
 680        RSZ_PRINT_REGISTER(isp, OUT_SIZE);
 681        RSZ_PRINT_REGISTER(isp, IN_START);
 682        RSZ_PRINT_REGISTER(isp, IN_SIZE);
 683        RSZ_PRINT_REGISTER(isp, SDR_INADD);
 684        RSZ_PRINT_REGISTER(isp, SDR_INOFF);
 685        RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
 686        RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
 687        RSZ_PRINT_REGISTER(isp, YENH);
 688
 689        dev_dbg(isp->dev, "--------------------------------------------\n");
 690}
 691
 692/*
 693 * resizer_calc_ratios - Helper function for calculate resizer ratios
 694 * @res: pointer to resizer private data structure
 695 * @input: input frame size
 696 * @output: output frame size
 697 * @ratio : return calculated ratios
 698 * return none
 699 *
 700 * The resizer uses a polyphase sample rate converter. The upsampling filter
 701 * has a fixed number of phases that depend on the resizing ratio. As the ratio
 702 * computation depends on the number of phases, we need to compute a first
 703 * approximation and then refine it.
 704 *
 705 * The input/output/ratio relationship is given by the OMAP34xx TRM:
 706 *
 707 * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
 708 *      iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
 709 *      ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
 710 * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
 711 *      iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
 712 *      ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
 713 *
 714 * iw and ih are the input width and height after cropping. Those equations need
 715 * to be satisfied exactly for the resizer to work correctly.
 716 *
 717 * The equations can't be easily reverted, as the >> 8 operation is not linear.
 718 * In addition, not all input sizes can be achieved for a given output size. To
 719 * get the highest input size lower than or equal to the requested input size,
 720 * we need to compute the highest resizing ratio that satisfies the following
 721 * inequality (taking the 4-tap mode width equation as an example)
 722 *
 723 *      iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
 724 *
 725 * (where iw is the requested input width) which can be rewritten as
 726 *
 727 *        iw - 7            >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
 728 *       (iw - 7) << 8      >=  32 * sph + (ow - 1) * hrsz + 16 - b
 729 *      ((iw - 7) << 8) + b >=  32 * sph + (ow - 1) * hrsz + 16
 730 *
 731 * where b is the value of the 8 least significant bits of the right hand side
 732 * expression of the last inequality. The highest resizing ratio value will be
 733 * achieved when b is equal to its maximum value of 255. That resizing ratio
 734 * value will still satisfy the original inequality, as b will disappear when
 735 * the expression will be shifted right by 8.
 736 *
 737 * The reverted the equations thus become
 738 *
 739 * - 8-phase, 4-tap mode
 740 *      hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
 741 *      vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
 742 * - 4-phase, 7-tap mode
 743 *      hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
 744 *      vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
 745 *
 746 * The ratios are integer values, and are rounded down to ensure that the
 747 * cropped input size is not bigger than the uncropped input size.
 748 *
 749 * As the number of phases/taps, used to select the correct equations to compute
 750 * the ratio, depends on the ratio, we start with the 4-tap mode equations to
 751 * compute an approximation of the ratio, and switch to the 7-tap mode equations
 752 * if the approximation is higher than the ratio threshold.
 753 *
 754 * As the 7-tap mode equations will return a ratio smaller than or equal to the
 755 * 4-tap mode equations, the resulting ratio could become lower than or equal to
 756 * the ratio threshold. This 'equations loop' isn't an issue as long as the
 757 * correct equations are used to compute the final input size. Starting with the
 758 * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
 759 * loop', the smallest of the ratio values will be used, never exceeding the
 760 * requested input size.
 761 *
 762 * We first clamp the output size according to the hardware capabilitie to avoid
 763 * auto-cropping the input more than required to satisfy the TRM equations. The
 764 * minimum output size is achieved with a scaling factor of 1024. It is thus
 765 * computed using the 7-tap equations.
 766 *
 767 *      min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
 768 *      min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
 769 *
 770 * Similarly, the maximum output size is achieved with a scaling factor of 64
 771 * and computed using the 4-tap equations.
 772 *
 773 *      max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
 774 *      max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
 775 *
 776 * The additional +255 term compensates for the round down operation performed
 777 * by the TRM equations when shifting the value right by 8 bits.
 778 *
 779 * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
 780 * the maximum value guarantees that the ratio value will never be smaller than
 781 * the minimum, but it could still slightly exceed the maximum. Clamping the
 782 * ratio will thus result in a resizing factor slightly larger than the
 783 * requested value.
 784 *
 785 * To accommodate that, and make sure the TRM equations are satisfied exactly, we
 786 * compute the input crop rectangle as the last step.
 787 *
 788 * As if the situation wasn't complex enough, the maximum output width depends
 789 * on the vertical resizing ratio.  Fortunately, the output height doesn't
 790 * depend on the horizontal resizing ratio. We can then start by computing the
 791 * output height and the vertical ratio, and then move to computing the output
 792 * width and the horizontal ratio.
 793 */
 794static void resizer_calc_ratios(struct isp_res_device *res,
 795                                struct v4l2_rect *input,
 796                                struct v4l2_mbus_framefmt *output,
 797                                struct resizer_ratio *ratio)
 798{
 799        struct isp_device *isp = to_isp_device(res);
 800        const unsigned int spv = DEFAULT_PHASE;
 801        const unsigned int sph = DEFAULT_PHASE;
 802        unsigned int upscaled_width;
 803        unsigned int upscaled_height;
 804        unsigned int min_width;
 805        unsigned int min_height;
 806        unsigned int max_width;
 807        unsigned int max_height;
 808        unsigned int width_alignment;
 809        unsigned int width;
 810        unsigned int height;
 811
 812        /*
 813         * Clamp the output height based on the hardware capabilities and
 814         * compute the vertical resizing ratio.
 815         */
 816        min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
 817        min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
 818        max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
 819        max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
 820        output->height = clamp(output->height, min_height, max_height);
 821
 822        ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
 823                    / (output->height - 1);
 824        if (ratio->vert > MID_RESIZE_VALUE)
 825                ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
 826                            / (output->height - 1);
 827        ratio->vert = clamp_t(unsigned int, ratio->vert,
 828                              MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
 829
 830        if (ratio->vert <= MID_RESIZE_VALUE) {
 831                upscaled_height = (output->height - 1) * ratio->vert
 832                                + 32 * spv + 16;
 833                height = (upscaled_height >> 8) + 4;
 834        } else {
 835                upscaled_height = (output->height - 1) * ratio->vert
 836                                + 64 * spv + 32;
 837                height = (upscaled_height >> 8) + 7;
 838        }
 839
 840        /*
 841         * Compute the minimum and maximum output widths based on the hardware
 842         * capabilities. The maximum depends on the vertical resizing ratio.
 843         */
 844        min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
 845        min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
 846
 847        if (ratio->vert <= MID_RESIZE_VALUE) {
 848                switch (isp->revision) {
 849                case ISP_REVISION_1_0:
 850                        max_width = MAX_4TAP_OUT_WIDTH_ES1;
 851                        break;
 852
 853                case ISP_REVISION_2_0:
 854                default:
 855                        max_width = MAX_4TAP_OUT_WIDTH_ES2;
 856                        break;
 857
 858                case ISP_REVISION_15_0:
 859                        max_width = MAX_4TAP_OUT_WIDTH_3630;
 860                        break;
 861                }
 862        } else {
 863                switch (isp->revision) {
 864                case ISP_REVISION_1_0:
 865                        max_width = MAX_7TAP_OUT_WIDTH_ES1;
 866                        break;
 867
 868                case ISP_REVISION_2_0:
 869                default:
 870                        max_width = MAX_7TAP_OUT_WIDTH_ES2;
 871                        break;
 872
 873                case ISP_REVISION_15_0:
 874                        max_width = MAX_7TAP_OUT_WIDTH_3630;
 875                        break;
 876                }
 877        }
 878        max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
 879                        + 1, max_width);
 880
 881        /*
 882         * The output width must be even, and must be a multiple of 16 bytes
 883         * when upscaling vertically. Clamp the output width to the valid range.
 884         * Take the alignment into account (the maximum width in 7-tap mode on
 885         * ES2 isn't a multiple of 8) and align the result up to make sure it
 886         * won't be smaller than the minimum.
 887         */
 888        width_alignment = ratio->vert < 256 ? 8 : 2;
 889        output->width = clamp(output->width, min_width,
 890                              max_width & ~(width_alignment - 1));
 891        output->width = ALIGN(output->width, width_alignment);
 892
 893        ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
 894                    / (output->width - 1);
 895        if (ratio->horz > MID_RESIZE_VALUE)
 896                ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
 897                            / (output->width - 1);
 898        ratio->horz = clamp_t(unsigned int, ratio->horz,
 899                              MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
 900
 901        if (ratio->horz <= MID_RESIZE_VALUE) {
 902                upscaled_width = (output->width - 1) * ratio->horz
 903                               + 32 * sph + 16;
 904                width = (upscaled_width >> 8) + 7;
 905        } else {
 906                upscaled_width = (output->width - 1) * ratio->horz
 907                               + 64 * sph + 32;
 908                width = (upscaled_width >> 8) + 7;
 909        }
 910
 911        /* Center the new crop rectangle. */
 912        input->left += (input->width - width) / 2;
 913        input->top += (input->height - height) / 2;
 914        input->width = width;
 915        input->height = height;
 916}
 917
 918/*
 919 * resizer_set_crop_params - Setup hardware with cropping parameters
 920 * @res : resizer private structure
 921 * @crop_rect : current crop rectangle
 922 * @ratio : resizer ratios
 923 * return none
 924 */
 925static void resizer_set_crop_params(struct isp_res_device *res,
 926                                    const struct v4l2_mbus_framefmt *input,
 927                                    const struct v4l2_mbus_framefmt *output)
 928{
 929        resizer_set_ratio(res, &res->ratio);
 930
 931        /* Set chrominance horizontal algorithm */
 932        if (res->ratio.horz >= RESIZE_DIVISOR)
 933                resizer_set_bilinear(res, RSZ_THE_SAME);
 934        else
 935                resizer_set_bilinear(res, RSZ_BILINEAR);
 936
 937        resizer_adjust_bandwidth(res);
 938
 939        if (res->input == RESIZER_INPUT_MEMORY) {
 940                /* Calculate additional offset for crop */
 941                res->crop_offset = (res->crop.active.top * input->width +
 942                                    res->crop.active.left) * 2;
 943                /*
 944                 * Write lowest 4 bits of horizontal pixel offset (in pixels),
 945                 * vertical start must be 0.
 946                 */
 947                resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
 948
 949                /*
 950                 * Set start (read) address for cropping, in bytes.
 951                 * Lowest 5 bits must be zero.
 952                 */
 953                __resizer_set_inaddr(res,
 954                                res->addr_base + (res->crop_offset & ~0x1f));
 955        } else {
 956                /*
 957                 * Set vertical start line and horizontal starting pixel.
 958                 * If the input is from CCDC/PREV, horizontal start field is
 959                 * in bytes (twice number of pixels).
 960                 */
 961                resizer_set_start(res, res->crop.active.left * 2,
 962                                  res->crop.active.top);
 963                /* Input address and offset must be 0 for preview/ccdc input */
 964                __resizer_set_inaddr(res, 0);
 965                resizer_set_input_offset(res, 0);
 966        }
 967
 968        /* Set the input size */
 969        resizer_set_input_size(res, res->crop.active.width,
 970                               res->crop.active.height);
 971}
 972
 973static void resizer_configure(struct isp_res_device *res)
 974{
 975        struct v4l2_mbus_framefmt *informat, *outformat;
 976        struct resizer_luma_yenh luma = {0, 0, 0, 0};
 977
 978        resizer_set_source(res, res->input);
 979
 980        informat = &res->formats[RESZ_PAD_SINK];
 981        outformat = &res->formats[RESZ_PAD_SOURCE];
 982
 983        /* RESZ_PAD_SINK */
 984        if (res->input == RESIZER_INPUT_VP)
 985                resizer_set_input_offset(res, 0);
 986        else
 987                resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
 988
 989        /* YUV422 interleaved, default phase, no luma enhancement */
 990        resizer_set_intype(res, RSZ_YUV422);
 991        resizer_set_ycpos(res, informat->code);
 992        resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
 993        resizer_set_luma(res, &luma);
 994
 995        /* RESZ_PAD_SOURCE */
 996        resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
 997        resizer_set_output_size(res, outformat->width, outformat->height);
 998
 999        resizer_set_crop_params(res, informat, outformat);
1000}
1001
1002/* -----------------------------------------------------------------------------
1003 * Interrupt handling
1004 */
1005
1006static void resizer_enable_oneshot(struct isp_res_device *res)
1007{
1008        struct isp_device *isp = to_isp_device(res);
1009
1010        isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
1011                    ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
1012}
1013
1014void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
1015{
1016        /*
1017         * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
1018         * condition, the module was paused and now we have a buffer queued
1019         * on the output again. Restart the pipeline if running in continuous
1020         * mode.
1021         */
1022        if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
1023            res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1024                resizer_enable_oneshot(res);
1025                isp_video_dmaqueue_flags_clr(&res->video_out);
1026        }
1027}
1028
1029static void resizer_isr_buffer(struct isp_res_device *res)
1030{
1031        struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
1032        struct isp_buffer *buffer;
1033        int restart = 0;
1034
1035        if (res->state == ISP_PIPELINE_STREAM_STOPPED)
1036                return;
1037
1038        /* Complete the output buffer and, if reading from memory, the input
1039         * buffer.
1040         */
1041        buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
1042        if (buffer != NULL) {
1043                resizer_set_outaddr(res, buffer->isp_addr);
1044                restart = 1;
1045        }
1046
1047        pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1048
1049        if (res->input == RESIZER_INPUT_MEMORY) {
1050                buffer = omap3isp_video_buffer_next(&res->video_in, 0);
1051                if (buffer != NULL)
1052                        resizer_set_inaddr(res, buffer->isp_addr);
1053                pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1054        }
1055
1056        if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
1057                if (isp_pipeline_ready(pipe))
1058                        omap3isp_pipeline_set_stream(pipe,
1059                                                ISP_PIPELINE_STREAM_SINGLESHOT);
1060        } else {
1061                /* If an underrun occurs, the video queue operation handler will
1062                 * restart the resizer. Otherwise restart it immediately.
1063                 */
1064                if (restart)
1065                        resizer_enable_oneshot(res);
1066        }
1067
1068        res->error = 0;
1069}
1070
1071/*
1072 * omap3isp_resizer_isr - ISP resizer interrupt handler
1073 *
1074 * Manage the resizer video buffers and configure shadowed and busy-locked
1075 * registers.
1076 */
1077void omap3isp_resizer_isr(struct isp_res_device *res)
1078{
1079        struct v4l2_mbus_framefmt *informat, *outformat;
1080
1081        if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1082                return;
1083
1084        if (res->applycrop) {
1085                outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1086                                              V4L2_SUBDEV_FORMAT_ACTIVE);
1087                informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1088                                              V4L2_SUBDEV_FORMAT_ACTIVE);
1089                resizer_set_crop_params(res, informat, outformat);
1090                res->applycrop = 0;
1091        }
1092
1093        resizer_isr_buffer(res);
1094}
1095
1096/* -----------------------------------------------------------------------------
1097 * ISP video operations
1098 */
1099
1100static int resizer_video_queue(struct isp_video *video,
1101                               struct isp_buffer *buffer)
1102{
1103        struct isp_res_device *res = &video->isp->isp_res;
1104
1105        if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1106                resizer_set_inaddr(res, buffer->isp_addr);
1107
1108        /*
1109         * We now have a buffer queued on the output. Despite what the
1110         * TRM says, the resizer can't be restarted immediately.
1111         * Enabling it in one shot mode in the middle of a frame (or at
1112         * least asynchronously to the frame) results in the output
1113         * being shifted randomly left/right and up/down, as if the
1114         * hardware didn't synchronize itself to the beginning of the
1115         * frame correctly.
1116         *
1117         * Restart the resizer on the next sync interrupt if running in
1118         * continuous mode or when starting the stream.
1119         */
1120        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1121                resizer_set_outaddr(res, buffer->isp_addr);
1122
1123        return 0;
1124}
1125
1126static const struct isp_video_operations resizer_video_ops = {
1127        .queue = resizer_video_queue,
1128};
1129
1130/* -----------------------------------------------------------------------------
1131 * V4L2 subdev operations
1132 */
1133
1134/*
1135 * resizer_set_stream - Enable/Disable streaming on resizer subdev
1136 * @sd: ISP resizer V4L2 subdev
1137 * @enable: 1 == Enable, 0 == Disable
1138 *
1139 * The resizer hardware can't be enabled without a memory buffer to write to.
1140 * As the s_stream operation is called in response to a STREAMON call without
1141 * any buffer queued yet, just update the state field and return immediately.
1142 * The resizer will be enabled in resizer_video_queue().
1143 */
1144static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1145{
1146        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1147        struct isp_video *video_out = &res->video_out;
1148        struct isp_device *isp = to_isp_device(res);
1149        struct device *dev = to_device(res);
1150
1151        if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1152                if (enable == ISP_PIPELINE_STREAM_STOPPED)
1153                        return 0;
1154
1155                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1156                resizer_configure(res);
1157                res->error = 0;
1158                resizer_print_status(res);
1159        }
1160
1161        switch (enable) {
1162        case ISP_PIPELINE_STREAM_CONTINUOUS:
1163                omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1164                if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1165                        resizer_enable_oneshot(res);
1166                        isp_video_dmaqueue_flags_clr(video_out);
1167                }
1168                break;
1169
1170        case ISP_PIPELINE_STREAM_SINGLESHOT:
1171                if (res->input == RESIZER_INPUT_MEMORY)
1172                        omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1173                omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1174
1175                resizer_enable_oneshot(res);
1176                break;
1177
1178        case ISP_PIPELINE_STREAM_STOPPED:
1179                if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1180                                              &res->stopping))
1181                        dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1182                omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1183                                OMAP3_ISP_SBL_RESIZER_WRITE);
1184                omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1185                isp_video_dmaqueue_flags_clr(video_out);
1186                break;
1187        }
1188
1189        res->state = enable;
1190        return 0;
1191}
1192
1193/*
1194 * resizer_g_crop - handle get crop subdev operation
1195 * @sd : pointer to v4l2 subdev structure
1196 * @pad : subdev pad
1197 * @crop : pointer to crop structure
1198 * @which : active or try format
1199 * return zero
1200 */
1201static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1202                          struct v4l2_subdev_crop *crop)
1203{
1204        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1205        struct v4l2_mbus_framefmt *format;
1206        struct resizer_ratio ratio;
1207
1208        /* Only sink pad has crop capability */
1209        if (crop->pad != RESZ_PAD_SINK)
1210                return -EINVAL;
1211
1212        format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1213        crop->rect = *__resizer_get_crop(res, fh, crop->which);
1214        resizer_calc_ratios(res, &crop->rect, format, &ratio);
1215
1216        return 0;
1217}
1218
1219/*
1220 * resizer_try_crop - mangles crop parameters.
1221 */
1222static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1223                             const struct v4l2_mbus_framefmt *source,
1224                             struct v4l2_rect *crop)
1225{
1226        const unsigned int spv = DEFAULT_PHASE;
1227        const unsigned int sph = DEFAULT_PHASE;
1228
1229        /* Crop rectangle is constrained to the output size so that zoom ratio
1230         * cannot exceed +/-4.0.
1231         */
1232        unsigned int min_width =
1233                ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1234        unsigned int min_height =
1235                ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1236        unsigned int max_width =
1237                ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1238        unsigned int max_height =
1239                ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1240
1241        crop->width = clamp_t(u32, crop->width, min_width, max_width);
1242        crop->height = clamp_t(u32, crop->height, min_height, max_height);
1243
1244        /* Crop can not go beyond of the input rectangle */
1245        crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1246        crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1247                              sink->width - crop->left);
1248        crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1249        crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1250                               sink->height - crop->top);
1251}
1252
1253/*
1254 * resizer_s_crop - handle set crop subdev operation
1255 * @sd : pointer to v4l2 subdev structure
1256 * @pad : subdev pad
1257 * @crop : pointer to crop structure
1258 * @which : active or try format
1259 * return -EINVAL or zero when succeed
1260 */
1261static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1262                          struct v4l2_subdev_crop *crop)
1263{
1264        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1265        struct isp_device *isp = to_isp_device(res);
1266        struct v4l2_mbus_framefmt *format_sink, *format_source;
1267        struct resizer_ratio ratio;
1268
1269        /* Only sink pad has crop capability */
1270        if (crop->pad != RESZ_PAD_SINK)
1271                return -EINVAL;
1272
1273        format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1274                                           crop->which);
1275        format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1276                                             crop->which);
1277
1278        dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1279                crop->rect.left, crop->rect.top, crop->rect.width,
1280                crop->rect.height, crop->which);
1281
1282        dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1283                format_sink->width, format_sink->height,
1284                format_source->width, format_source->height);
1285
1286        resizer_try_crop(format_sink, format_source, &crop->rect);
1287        *__resizer_get_crop(res, fh, crop->which) = crop->rect;
1288        resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1289
1290        if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1291                return 0;
1292
1293        res->ratio = ratio;
1294        res->crop.active = crop->rect;
1295
1296        /*
1297         * s_crop can be called while streaming is on. In this case
1298         * the crop values will be set in the next IRQ.
1299         */
1300        if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1301                res->applycrop = 1;
1302
1303        return 0;
1304}
1305
1306/* resizer pixel formats */
1307static const unsigned int resizer_formats[] = {
1308        V4L2_MBUS_FMT_UYVY8_1X16,
1309        V4L2_MBUS_FMT_YUYV8_1X16,
1310};
1311
1312static unsigned int resizer_max_in_width(struct isp_res_device *res)
1313{
1314        struct isp_device *isp = to_isp_device(res);
1315
1316        if (res->input == RESIZER_INPUT_MEMORY) {
1317                return MAX_IN_WIDTH_MEMORY_MODE;
1318        } else {
1319                if (isp->revision == ISP_REVISION_1_0)
1320                        return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1321                else
1322                        return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1323        }
1324}
1325
1326/*
1327 * resizer_try_format - Handle try format by pad subdev method
1328 * @res   : ISP resizer device
1329 * @fh    : V4L2 subdev file handle
1330 * @pad   : pad num
1331 * @fmt   : pointer to v4l2 format structure
1332 * @which : wanted subdev format
1333 */
1334static void resizer_try_format(struct isp_res_device *res,
1335                               struct v4l2_subdev_fh *fh, unsigned int pad,
1336                               struct v4l2_mbus_framefmt *fmt,
1337                               enum v4l2_subdev_format_whence which)
1338{
1339        struct v4l2_mbus_framefmt *format;
1340        struct resizer_ratio ratio;
1341        struct v4l2_rect crop;
1342
1343        switch (pad) {
1344        case RESZ_PAD_SINK:
1345                if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1346                    fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1347                        fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1348
1349                fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1350                                     resizer_max_in_width(res));
1351                fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1352                                      MAX_IN_HEIGHT);
1353                break;
1354
1355        case RESZ_PAD_SOURCE:
1356                format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1357                fmt->code = format->code;
1358
1359                crop = *__resizer_get_crop(res, fh, which);
1360                resizer_calc_ratios(res, &crop, fmt, &ratio);
1361                break;
1362        }
1363
1364        fmt->colorspace = V4L2_COLORSPACE_JPEG;
1365        fmt->field = V4L2_FIELD_NONE;
1366}
1367
1368/*
1369 * resizer_enum_mbus_code - Handle pixel format enumeration
1370 * @sd     : pointer to v4l2 subdev structure
1371 * @fh     : V4L2 subdev file handle
1372 * @code   : pointer to v4l2_subdev_mbus_code_enum structure
1373 * return -EINVAL or zero on success
1374 */
1375static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1376                                  struct v4l2_subdev_fh *fh,
1377                                  struct v4l2_subdev_mbus_code_enum *code)
1378{
1379        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1380        struct v4l2_mbus_framefmt *format;
1381
1382        if (code->pad == RESZ_PAD_SINK) {
1383                if (code->index >= ARRAY_SIZE(resizer_formats))
1384                        return -EINVAL;
1385
1386                code->code = resizer_formats[code->index];
1387        } else {
1388                if (code->index != 0)
1389                        return -EINVAL;
1390
1391                format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1392                                              V4L2_SUBDEV_FORMAT_TRY);
1393                code->code = format->code;
1394        }
1395
1396        return 0;
1397}
1398
1399static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1400                                   struct v4l2_subdev_fh *fh,
1401                                   struct v4l2_subdev_frame_size_enum *fse)
1402{
1403        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1404        struct v4l2_mbus_framefmt format;
1405
1406        if (fse->index != 0)
1407                return -EINVAL;
1408
1409        format.code = fse->code;
1410        format.width = 1;
1411        format.height = 1;
1412        resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1413        fse->min_width = format.width;
1414        fse->min_height = format.height;
1415
1416        if (format.code != fse->code)
1417                return -EINVAL;
1418
1419        format.code = fse->code;
1420        format.width = -1;
1421        format.height = -1;
1422        resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1423        fse->max_width = format.width;
1424        fse->max_height = format.height;
1425
1426        return 0;
1427}
1428
1429/*
1430 * resizer_get_format - Handle get format by pads subdev method
1431 * @sd    : pointer to v4l2 subdev structure
1432 * @fh    : V4L2 subdev file handle
1433 * @fmt   : pointer to v4l2 subdev format structure
1434 * return -EINVAL or zero on success
1435 */
1436static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1437                              struct v4l2_subdev_format *fmt)
1438{
1439        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1440        struct v4l2_mbus_framefmt *format;
1441
1442        format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1443        if (format == NULL)
1444                return -EINVAL;
1445
1446        fmt->format = *format;
1447        return 0;
1448}
1449
1450/*
1451 * resizer_set_format - Handle set format by pads subdev method
1452 * @sd    : pointer to v4l2 subdev structure
1453 * @fh    : V4L2 subdev file handle
1454 * @fmt   : pointer to v4l2 subdev format structure
1455 * return -EINVAL or zero on success
1456 */
1457static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1458                              struct v4l2_subdev_format *fmt)
1459{
1460        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1461        struct v4l2_mbus_framefmt *format;
1462        struct v4l2_rect *crop;
1463
1464        format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1465        if (format == NULL)
1466                return -EINVAL;
1467
1468        resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1469        *format = fmt->format;
1470
1471        if (fmt->pad == RESZ_PAD_SINK) {
1472                /* reset crop rectangle */
1473                crop = __resizer_get_crop(res, fh, fmt->which);
1474                crop->left = 0;
1475                crop->top = 0;
1476                crop->width = fmt->format.width;
1477                crop->height = fmt->format.height;
1478
1479                /* Propagate the format from sink to source */
1480                format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1481                                              fmt->which);
1482                *format = fmt->format;
1483                resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1484                                   fmt->which);
1485        }
1486
1487        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1488                /* Compute and store the active crop rectangle and resizer
1489                 * ratios. format already points to the source pad active
1490                 * format.
1491                 */
1492                res->crop.active = res->crop.request;
1493                resizer_calc_ratios(res, &res->crop.active, format,
1494                                       &res->ratio);
1495        }
1496
1497        return 0;
1498}
1499
1500/*
1501 * resizer_init_formats - Initialize formats on all pads
1502 * @sd: ISP resizer V4L2 subdevice
1503 * @fh: V4L2 subdev file handle
1504 *
1505 * Initialize all pad formats with default values. If fh is not NULL, try
1506 * formats are initialized on the file handle. Otherwise active formats are
1507 * initialized on the device.
1508 */
1509static int resizer_init_formats(struct v4l2_subdev *sd,
1510                                struct v4l2_subdev_fh *fh)
1511{
1512        struct v4l2_subdev_format format;
1513
1514        memset(&format, 0, sizeof(format));
1515        format.pad = RESZ_PAD_SINK;
1516        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1517        format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1518        format.format.width = 4096;
1519        format.format.height = 4096;
1520        resizer_set_format(sd, fh, &format);
1521
1522        return 0;
1523}
1524
1525/* subdev video operations */
1526static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1527        .s_stream = resizer_set_stream,
1528};
1529
1530/* subdev pad operations */
1531static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1532        .enum_mbus_code = resizer_enum_mbus_code,
1533        .enum_frame_size = resizer_enum_frame_size,
1534        .get_fmt = resizer_get_format,
1535        .set_fmt = resizer_set_format,
1536        .get_crop = resizer_g_crop,
1537        .set_crop = resizer_s_crop,
1538};
1539
1540/* subdev operations */
1541static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1542        .video = &resizer_v4l2_video_ops,
1543        .pad = &resizer_v4l2_pad_ops,
1544};
1545
1546/* subdev internal operations */
1547static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1548        .open = resizer_init_formats,
1549};
1550
1551/* -----------------------------------------------------------------------------
1552 * Media entity operations
1553 */
1554
1555/*
1556 * resizer_link_setup - Setup resizer connections.
1557 * @entity : Pointer to media entity structure
1558 * @local  : Pointer to local pad array
1559 * @remote : Pointer to remote pad array
1560 * @flags  : Link flags
1561 * return -EINVAL or zero on success
1562 */
1563static int resizer_link_setup(struct media_entity *entity,
1564                              const struct media_pad *local,
1565                              const struct media_pad *remote, u32 flags)
1566{
1567        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1568        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1569
1570        switch (local->index | media_entity_type(remote->entity)) {
1571        case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1572                /* read from memory */
1573                if (flags & MEDIA_LNK_FL_ENABLED) {
1574                        if (res->input == RESIZER_INPUT_VP)
1575                                return -EBUSY;
1576                        res->input = RESIZER_INPUT_MEMORY;
1577                } else {
1578                        if (res->input == RESIZER_INPUT_MEMORY)
1579                                res->input = RESIZER_INPUT_NONE;
1580                }
1581                break;
1582
1583        case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1584                /* read from ccdc or previewer */
1585                if (flags & MEDIA_LNK_FL_ENABLED) {
1586                        if (res->input == RESIZER_INPUT_MEMORY)
1587                                return -EBUSY;
1588                        res->input = RESIZER_INPUT_VP;
1589                } else {
1590                        if (res->input == RESIZER_INPUT_VP)
1591                                res->input = RESIZER_INPUT_NONE;
1592                }
1593                break;
1594
1595        case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1596                /* resizer always write to memory */
1597                break;
1598
1599        default:
1600                return -EINVAL;
1601        }
1602
1603        return 0;
1604}
1605
1606/* media operations */
1607static const struct media_entity_operations resizer_media_ops = {
1608        .link_setup = resizer_link_setup,
1609};
1610
1611/*
1612 * resizer_init_entities - Initialize resizer subdev and media entity.
1613 * @res : Pointer to resizer device structure
1614 * return -ENOMEM or zero on success
1615 */
1616static int resizer_init_entities(struct isp_res_device *res)
1617{
1618        struct v4l2_subdev *sd = &res->subdev;
1619        struct media_pad *pads = res->pads;
1620        struct media_entity *me = &sd->entity;
1621        int ret;
1622
1623        res->input = RESIZER_INPUT_NONE;
1624
1625        v4l2_subdev_init(sd, &resizer_v4l2_ops);
1626        sd->internal_ops = &resizer_v4l2_internal_ops;
1627        strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1628        sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
1629        v4l2_set_subdevdata(sd, res);
1630        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1631
1632        pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1633        pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1634
1635        me->ops = &resizer_media_ops;
1636        ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1637        if (ret < 0)
1638                return ret;
1639
1640        resizer_init_formats(sd, NULL);
1641
1642        res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1643        res->video_in.ops = &resizer_video_ops;
1644        res->video_in.isp = to_isp_device(res);
1645        res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1646        res->video_in.bpl_alignment = 32;
1647        res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1648        res->video_out.ops = &resizer_video_ops;
1649        res->video_out.isp = to_isp_device(res);
1650        res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1651        res->video_out.bpl_alignment = 32;
1652
1653        ret = omap3isp_video_init(&res->video_in, "resizer");
1654        if (ret < 0)
1655                return ret;
1656
1657        ret = omap3isp_video_init(&res->video_out, "resizer");
1658        if (ret < 0)
1659                return ret;
1660
1661        /* Connect the video nodes to the resizer subdev. */
1662        ret = media_entity_create_link(&res->video_in.video.entity, 0,
1663                        &res->subdev.entity, RESZ_PAD_SINK, 0);
1664        if (ret < 0)
1665                return ret;
1666
1667        ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1668                        &res->video_out.video.entity, 0, 0);
1669        if (ret < 0)
1670                return ret;
1671
1672        return 0;
1673}
1674
1675void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1676{
1677        media_entity_cleanup(&res->subdev.entity);
1678
1679        v4l2_device_unregister_subdev(&res->subdev);
1680        omap3isp_video_unregister(&res->video_in);
1681        omap3isp_video_unregister(&res->video_out);
1682}
1683
1684int omap3isp_resizer_register_entities(struct isp_res_device *res,
1685                                       struct v4l2_device *vdev)
1686{
1687        int ret;
1688
1689        /* Register the subdev and video nodes. */
1690        ret = v4l2_device_register_subdev(vdev, &res->subdev);
1691        if (ret < 0)
1692                goto error;
1693
1694        ret = omap3isp_video_register(&res->video_in, vdev);
1695        if (ret < 0)
1696                goto error;
1697
1698        ret = omap3isp_video_register(&res->video_out, vdev);
1699        if (ret < 0)
1700                goto error;
1701
1702        return 0;
1703
1704error:
1705        omap3isp_resizer_unregister_entities(res);
1706        return ret;
1707}
1708
1709/* -----------------------------------------------------------------------------
1710 * ISP resizer initialization and cleanup
1711 */
1712
1713void omap3isp_resizer_cleanup(struct isp_device *isp)
1714{
1715}
1716
1717/*
1718 * isp_resizer_init - Resizer initialization.
1719 * @isp : Pointer to ISP device
1720 * return -ENOMEM or zero on success
1721 */
1722int omap3isp_resizer_init(struct isp_device *isp)
1723{
1724        struct isp_res_device *res = &isp->isp_res;
1725        int ret;
1726
1727        init_waitqueue_head(&res->wait);
1728        atomic_set(&res->stopping, 0);
1729        ret = resizer_init_entities(res);
1730        if (ret < 0)
1731                goto out;
1732
1733out:
1734        if (ret)
1735                omap3isp_resizer_cleanup(isp);
1736
1737        return ret;
1738}
1739