linux/drivers/media/platform/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 calculating 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 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 capability 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);
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);
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
1069/*
1070 * omap3isp_resizer_isr - ISP resizer interrupt handler
1071 *
1072 * Manage the resizer video buffers and configure shadowed and busy-locked
1073 * registers.
1074 */
1075void omap3isp_resizer_isr(struct isp_res_device *res)
1076{
1077        struct v4l2_mbus_framefmt *informat, *outformat;
1078
1079        if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1080                return;
1081
1082        if (res->applycrop) {
1083                outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1084                                              V4L2_SUBDEV_FORMAT_ACTIVE);
1085                informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1086                                              V4L2_SUBDEV_FORMAT_ACTIVE);
1087                resizer_set_crop_params(res, informat, outformat);
1088                res->applycrop = 0;
1089        }
1090
1091        resizer_isr_buffer(res);
1092}
1093
1094/* -----------------------------------------------------------------------------
1095 * ISP video operations
1096 */
1097
1098static int resizer_video_queue(struct isp_video *video,
1099                               struct isp_buffer *buffer)
1100{
1101        struct isp_res_device *res = &video->isp->isp_res;
1102
1103        if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1104                resizer_set_inaddr(res, buffer->isp_addr);
1105
1106        /*
1107         * We now have a buffer queued on the output. Despite what the
1108         * TRM says, the resizer can't be restarted immediately.
1109         * Enabling it in one shot mode in the middle of a frame (or at
1110         * least asynchronously to the frame) results in the output
1111         * being shifted randomly left/right and up/down, as if the
1112         * hardware didn't synchronize itself to the beginning of the
1113         * frame correctly.
1114         *
1115         * Restart the resizer on the next sync interrupt if running in
1116         * continuous mode or when starting the stream.
1117         */
1118        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1119                resizer_set_outaddr(res, buffer->isp_addr);
1120
1121        return 0;
1122}
1123
1124static const struct isp_video_operations resizer_video_ops = {
1125        .queue = resizer_video_queue,
1126};
1127
1128/* -----------------------------------------------------------------------------
1129 * V4L2 subdev operations
1130 */
1131
1132/*
1133 * resizer_set_stream - Enable/Disable streaming on resizer subdev
1134 * @sd: ISP resizer V4L2 subdev
1135 * @enable: 1 == Enable, 0 == Disable
1136 *
1137 * The resizer hardware can't be enabled without a memory buffer to write to.
1138 * As the s_stream operation is called in response to a STREAMON call without
1139 * any buffer queued yet, just update the state field and return immediately.
1140 * The resizer will be enabled in resizer_video_queue().
1141 */
1142static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1143{
1144        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1145        struct isp_video *video_out = &res->video_out;
1146        struct isp_device *isp = to_isp_device(res);
1147        struct device *dev = to_device(res);
1148
1149        if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1150                if (enable == ISP_PIPELINE_STREAM_STOPPED)
1151                        return 0;
1152
1153                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1154                resizer_configure(res);
1155                resizer_print_status(res);
1156        }
1157
1158        switch (enable) {
1159        case ISP_PIPELINE_STREAM_CONTINUOUS:
1160                omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1161                if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1162                        resizer_enable_oneshot(res);
1163                        isp_video_dmaqueue_flags_clr(video_out);
1164                }
1165                break;
1166
1167        case ISP_PIPELINE_STREAM_SINGLESHOT:
1168                if (res->input == RESIZER_INPUT_MEMORY)
1169                        omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1170                omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1171
1172                resizer_enable_oneshot(res);
1173                break;
1174
1175        case ISP_PIPELINE_STREAM_STOPPED:
1176                if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1177                                              &res->stopping))
1178                        dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1179                omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1180                                OMAP3_ISP_SBL_RESIZER_WRITE);
1181                omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1182                isp_video_dmaqueue_flags_clr(video_out);
1183                break;
1184        }
1185
1186        res->state = enable;
1187        return 0;
1188}
1189
1190/*
1191 * resizer_try_crop - mangles crop parameters.
1192 */
1193static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1194                             const struct v4l2_mbus_framefmt *source,
1195                             struct v4l2_rect *crop)
1196{
1197        const unsigned int spv = DEFAULT_PHASE;
1198        const unsigned int sph = DEFAULT_PHASE;
1199
1200        /* Crop rectangle is constrained by the output size so that zoom ratio
1201         * cannot exceed +/-4.0.
1202         */
1203        unsigned int min_width =
1204                ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1205        unsigned int min_height =
1206                ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1207        unsigned int max_width =
1208                ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1209        unsigned int max_height =
1210                ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1211
1212        crop->width = clamp_t(u32, crop->width, min_width, max_width);
1213        crop->height = clamp_t(u32, crop->height, min_height, max_height);
1214
1215        /* Crop can not go beyond of the input rectangle */
1216        crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1217        crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1218                              sink->width - crop->left);
1219        crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1220        crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1221                               sink->height - crop->top);
1222}
1223
1224/*
1225 * resizer_get_selection - Retrieve a selection rectangle on a pad
1226 * @sd: ISP resizer V4L2 subdevice
1227 * @fh: V4L2 subdev file handle
1228 * @sel: Selection rectangle
1229 *
1230 * The only supported rectangles are the crop rectangles on the sink pad.
1231 *
1232 * Return 0 on success or a negative error code otherwise.
1233 */
1234static int resizer_get_selection(struct v4l2_subdev *sd,
1235                                 struct v4l2_subdev_fh *fh,
1236                                 struct v4l2_subdev_selection *sel)
1237{
1238        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1239        struct v4l2_mbus_framefmt *format_source;
1240        struct v4l2_mbus_framefmt *format_sink;
1241        struct resizer_ratio ratio;
1242
1243        if (sel->pad != RESZ_PAD_SINK)
1244                return -EINVAL;
1245
1246        format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1247                                           sel->which);
1248        format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1249                                             sel->which);
1250
1251        switch (sel->target) {
1252        case V4L2_SEL_TGT_CROP_BOUNDS:
1253                sel->r.left = 0;
1254                sel->r.top = 0;
1255                sel->r.width = INT_MAX;
1256                sel->r.height = INT_MAX;
1257
1258                resizer_try_crop(format_sink, format_source, &sel->r);
1259                resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1260                break;
1261
1262        case V4L2_SEL_TGT_CROP:
1263                sel->r = *__resizer_get_crop(res, fh, sel->which);
1264                resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1265                break;
1266
1267        default:
1268                return -EINVAL;
1269        }
1270
1271        return 0;
1272}
1273
1274/*
1275 * resizer_set_selection - Set a selection rectangle on a pad
1276 * @sd: ISP resizer V4L2 subdevice
1277 * @fh: V4L2 subdev file handle
1278 * @sel: Selection rectangle
1279 *
1280 * The only supported rectangle is the actual crop rectangle on the sink pad.
1281 *
1282 * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
1283 * was always set.
1284 *
1285 * Return 0 on success or a negative error code otherwise.
1286 */
1287static int resizer_set_selection(struct v4l2_subdev *sd,
1288                                 struct v4l2_subdev_fh *fh,
1289                                 struct v4l2_subdev_selection *sel)
1290{
1291        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1292        struct isp_device *isp = to_isp_device(res);
1293        struct v4l2_mbus_framefmt *format_sink, *format_source;
1294        struct resizer_ratio ratio;
1295
1296        if (sel->target != V4L2_SEL_TGT_CROP ||
1297            sel->pad != RESZ_PAD_SINK)
1298                return -EINVAL;
1299
1300        format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1301                                           sel->which);
1302        format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1303                                             sel->which);
1304
1305        dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1306                sel->r.left, sel->r.top, sel->r.width, sel->r.height,
1307                sel->which);
1308
1309        dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1310                format_sink->width, format_sink->height,
1311                format_source->width, format_source->height);
1312
1313        /* Clamp the crop rectangle to the bounds, and then mangle it further to
1314         * fulfill the TRM equations. Store the clamped but otherwise unmangled
1315         * rectangle to avoid cropping the input multiple times: when an
1316         * application sets the output format, the current crop rectangle is
1317         * mangled during crop rectangle computation, which would lead to a new,
1318         * smaller input crop rectangle every time the output size is set if we
1319         * stored the mangled rectangle.
1320         */
1321        resizer_try_crop(format_sink, format_source, &sel->r);
1322        *__resizer_get_crop(res, fh, sel->which) = sel->r;
1323        resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1324
1325        if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
1326                return 0;
1327
1328        res->ratio = ratio;
1329        res->crop.active = sel->r;
1330
1331        /*
1332         * set_selection can be called while streaming is on. In this case the
1333         * crop values will be set in the next IRQ.
1334         */
1335        if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1336                res->applycrop = 1;
1337
1338        return 0;
1339}
1340
1341/* resizer pixel formats */
1342static const unsigned int resizer_formats[] = {
1343        V4L2_MBUS_FMT_UYVY8_1X16,
1344        V4L2_MBUS_FMT_YUYV8_1X16,
1345};
1346
1347static unsigned int resizer_max_in_width(struct isp_res_device *res)
1348{
1349        struct isp_device *isp = to_isp_device(res);
1350
1351        if (res->input == RESIZER_INPUT_MEMORY) {
1352                return MAX_IN_WIDTH_MEMORY_MODE;
1353        } else {
1354                if (isp->revision == ISP_REVISION_1_0)
1355                        return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1356                else
1357                        return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1358        }
1359}
1360
1361/*
1362 * resizer_try_format - Handle try format by pad subdev method
1363 * @res   : ISP resizer device
1364 * @fh    : V4L2 subdev file handle
1365 * @pad   : pad num
1366 * @fmt   : pointer to v4l2 format structure
1367 * @which : wanted subdev format
1368 */
1369static void resizer_try_format(struct isp_res_device *res,
1370                               struct v4l2_subdev_fh *fh, unsigned int pad,
1371                               struct v4l2_mbus_framefmt *fmt,
1372                               enum v4l2_subdev_format_whence which)
1373{
1374        struct v4l2_mbus_framefmt *format;
1375        struct resizer_ratio ratio;
1376        struct v4l2_rect crop;
1377
1378        switch (pad) {
1379        case RESZ_PAD_SINK:
1380                if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1381                    fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1382                        fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1383
1384                fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1385                                     resizer_max_in_width(res));
1386                fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1387                                      MAX_IN_HEIGHT);
1388                break;
1389
1390        case RESZ_PAD_SOURCE:
1391                format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1392                fmt->code = format->code;
1393
1394                crop = *__resizer_get_crop(res, fh, which);
1395                resizer_calc_ratios(res, &crop, fmt, &ratio);
1396                break;
1397        }
1398
1399        fmt->colorspace = V4L2_COLORSPACE_JPEG;
1400        fmt->field = V4L2_FIELD_NONE;
1401}
1402
1403/*
1404 * resizer_enum_mbus_code - Handle pixel format enumeration
1405 * @sd     : pointer to v4l2 subdev structure
1406 * @fh     : V4L2 subdev file handle
1407 * @code   : pointer to v4l2_subdev_mbus_code_enum structure
1408 * return -EINVAL or zero on success
1409 */
1410static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1411                                  struct v4l2_subdev_fh *fh,
1412                                  struct v4l2_subdev_mbus_code_enum *code)
1413{
1414        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1415        struct v4l2_mbus_framefmt *format;
1416
1417        if (code->pad == RESZ_PAD_SINK) {
1418                if (code->index >= ARRAY_SIZE(resizer_formats))
1419                        return -EINVAL;
1420
1421                code->code = resizer_formats[code->index];
1422        } else {
1423                if (code->index != 0)
1424                        return -EINVAL;
1425
1426                format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1427                                              V4L2_SUBDEV_FORMAT_TRY);
1428                code->code = format->code;
1429        }
1430
1431        return 0;
1432}
1433
1434static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1435                                   struct v4l2_subdev_fh *fh,
1436                                   struct v4l2_subdev_frame_size_enum *fse)
1437{
1438        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1439        struct v4l2_mbus_framefmt format;
1440
1441        if (fse->index != 0)
1442                return -EINVAL;
1443
1444        format.code = fse->code;
1445        format.width = 1;
1446        format.height = 1;
1447        resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1448        fse->min_width = format.width;
1449        fse->min_height = format.height;
1450
1451        if (format.code != fse->code)
1452                return -EINVAL;
1453
1454        format.code = fse->code;
1455        format.width = -1;
1456        format.height = -1;
1457        resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1458        fse->max_width = format.width;
1459        fse->max_height = format.height;
1460
1461        return 0;
1462}
1463
1464/*
1465 * resizer_get_format - Handle get format by pads subdev method
1466 * @sd    : pointer to v4l2 subdev structure
1467 * @fh    : V4L2 subdev file handle
1468 * @fmt   : pointer to v4l2 subdev format structure
1469 * return -EINVAL or zero on success
1470 */
1471static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1472                              struct v4l2_subdev_format *fmt)
1473{
1474        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1475        struct v4l2_mbus_framefmt *format;
1476
1477        format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1478        if (format == NULL)
1479                return -EINVAL;
1480
1481        fmt->format = *format;
1482        return 0;
1483}
1484
1485/*
1486 * resizer_set_format - Handle set format by pads subdev method
1487 * @sd    : pointer to v4l2 subdev structure
1488 * @fh    : V4L2 subdev file handle
1489 * @fmt   : pointer to v4l2 subdev format structure
1490 * return -EINVAL or zero on success
1491 */
1492static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1493                              struct v4l2_subdev_format *fmt)
1494{
1495        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1496        struct v4l2_mbus_framefmt *format;
1497        struct v4l2_rect *crop;
1498
1499        format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1500        if (format == NULL)
1501                return -EINVAL;
1502
1503        resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1504        *format = fmt->format;
1505
1506        if (fmt->pad == RESZ_PAD_SINK) {
1507                /* reset crop rectangle */
1508                crop = __resizer_get_crop(res, fh, fmt->which);
1509                crop->left = 0;
1510                crop->top = 0;
1511                crop->width = fmt->format.width;
1512                crop->height = fmt->format.height;
1513
1514                /* Propagate the format from sink to source */
1515                format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1516                                              fmt->which);
1517                *format = fmt->format;
1518                resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1519                                   fmt->which);
1520        }
1521
1522        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1523                /* Compute and store the active crop rectangle and resizer
1524                 * ratios. format already points to the source pad active
1525                 * format.
1526                 */
1527                res->crop.active = res->crop.request;
1528                resizer_calc_ratios(res, &res->crop.active, format,
1529                                       &res->ratio);
1530        }
1531
1532        return 0;
1533}
1534
1535static int resizer_link_validate(struct v4l2_subdev *sd,
1536                                 struct media_link *link,
1537                                 struct v4l2_subdev_format *source_fmt,
1538                                 struct v4l2_subdev_format *sink_fmt)
1539{
1540        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1541        struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
1542
1543        omap3isp_resizer_max_rate(res, &pipe->max_rate);
1544
1545        return v4l2_subdev_link_validate_default(sd, link,
1546                                                 source_fmt, sink_fmt);
1547}
1548
1549/*
1550 * resizer_init_formats - Initialize formats on all pads
1551 * @sd: ISP resizer V4L2 subdevice
1552 * @fh: V4L2 subdev file handle
1553 *
1554 * Initialize all pad formats with default values. If fh is not NULL, try
1555 * formats are initialized on the file handle. Otherwise active formats are
1556 * initialized on the device.
1557 */
1558static int resizer_init_formats(struct v4l2_subdev *sd,
1559                                struct v4l2_subdev_fh *fh)
1560{
1561        struct v4l2_subdev_format format;
1562
1563        memset(&format, 0, sizeof(format));
1564        format.pad = RESZ_PAD_SINK;
1565        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1566        format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1567        format.format.width = 4096;
1568        format.format.height = 4096;
1569        resizer_set_format(sd, fh, &format);
1570
1571        return 0;
1572}
1573
1574/* subdev video operations */
1575static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1576        .s_stream = resizer_set_stream,
1577};
1578
1579/* subdev pad operations */
1580static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1581        .enum_mbus_code = resizer_enum_mbus_code,
1582        .enum_frame_size = resizer_enum_frame_size,
1583        .get_fmt = resizer_get_format,
1584        .set_fmt = resizer_set_format,
1585        .get_selection = resizer_get_selection,
1586        .set_selection = resizer_set_selection,
1587        .link_validate = resizer_link_validate,
1588};
1589
1590/* subdev operations */
1591static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1592        .video = &resizer_v4l2_video_ops,
1593        .pad = &resizer_v4l2_pad_ops,
1594};
1595
1596/* subdev internal operations */
1597static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1598        .open = resizer_init_formats,
1599};
1600
1601/* -----------------------------------------------------------------------------
1602 * Media entity operations
1603 */
1604
1605/*
1606 * resizer_link_setup - Setup resizer connections.
1607 * @entity : Pointer to media entity structure
1608 * @local  : Pointer to local pad array
1609 * @remote : Pointer to remote pad array
1610 * @flags  : Link flags
1611 * return -EINVAL or zero on success
1612 */
1613static int resizer_link_setup(struct media_entity *entity,
1614                              const struct media_pad *local,
1615                              const struct media_pad *remote, u32 flags)
1616{
1617        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1618        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1619
1620        switch (local->index | media_entity_type(remote->entity)) {
1621        case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1622                /* read from memory */
1623                if (flags & MEDIA_LNK_FL_ENABLED) {
1624                        if (res->input == RESIZER_INPUT_VP)
1625                                return -EBUSY;
1626                        res->input = RESIZER_INPUT_MEMORY;
1627                } else {
1628                        if (res->input == RESIZER_INPUT_MEMORY)
1629                                res->input = RESIZER_INPUT_NONE;
1630                }
1631                break;
1632
1633        case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1634                /* read from ccdc or previewer */
1635                if (flags & MEDIA_LNK_FL_ENABLED) {
1636                        if (res->input == RESIZER_INPUT_MEMORY)
1637                                return -EBUSY;
1638                        res->input = RESIZER_INPUT_VP;
1639                } else {
1640                        if (res->input == RESIZER_INPUT_VP)
1641                                res->input = RESIZER_INPUT_NONE;
1642                }
1643                break;
1644
1645        case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1646                /* resizer always write to memory */
1647                break;
1648
1649        default:
1650                return -EINVAL;
1651        }
1652
1653        return 0;
1654}
1655
1656/* media operations */
1657static const struct media_entity_operations resizer_media_ops = {
1658        .link_setup = resizer_link_setup,
1659        .link_validate = v4l2_subdev_link_validate,
1660};
1661
1662void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1663{
1664        v4l2_device_unregister_subdev(&res->subdev);
1665        omap3isp_video_unregister(&res->video_in);
1666        omap3isp_video_unregister(&res->video_out);
1667}
1668
1669int omap3isp_resizer_register_entities(struct isp_res_device *res,
1670                                       struct v4l2_device *vdev)
1671{
1672        int ret;
1673
1674        /* Register the subdev and video nodes. */
1675        ret = v4l2_device_register_subdev(vdev, &res->subdev);
1676        if (ret < 0)
1677                goto error;
1678
1679        ret = omap3isp_video_register(&res->video_in, vdev);
1680        if (ret < 0)
1681                goto error;
1682
1683        ret = omap3isp_video_register(&res->video_out, vdev);
1684        if (ret < 0)
1685                goto error;
1686
1687        return 0;
1688
1689error:
1690        omap3isp_resizer_unregister_entities(res);
1691        return ret;
1692}
1693
1694/* -----------------------------------------------------------------------------
1695 * ISP resizer initialization and cleanup
1696 */
1697
1698/*
1699 * resizer_init_entities - Initialize resizer subdev and media entity.
1700 * @res : Pointer to resizer device structure
1701 * return -ENOMEM or zero on success
1702 */
1703static int resizer_init_entities(struct isp_res_device *res)
1704{
1705        struct v4l2_subdev *sd = &res->subdev;
1706        struct media_pad *pads = res->pads;
1707        struct media_entity *me = &sd->entity;
1708        int ret;
1709
1710        res->input = RESIZER_INPUT_NONE;
1711
1712        v4l2_subdev_init(sd, &resizer_v4l2_ops);
1713        sd->internal_ops = &resizer_v4l2_internal_ops;
1714        strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1715        sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
1716        v4l2_set_subdevdata(sd, res);
1717        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1718
1719        pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
1720                                    | MEDIA_PAD_FL_MUST_CONNECT;
1721        pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1722
1723        me->ops = &resizer_media_ops;
1724        ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1725        if (ret < 0)
1726                return ret;
1727
1728        resizer_init_formats(sd, NULL);
1729
1730        res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1731        res->video_in.ops = &resizer_video_ops;
1732        res->video_in.isp = to_isp_device(res);
1733        res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1734        res->video_in.bpl_alignment = 32;
1735        res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1736        res->video_out.ops = &resizer_video_ops;
1737        res->video_out.isp = to_isp_device(res);
1738        res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1739        res->video_out.bpl_alignment = 32;
1740
1741        ret = omap3isp_video_init(&res->video_in, "resizer");
1742        if (ret < 0)
1743                goto error_video_in;
1744
1745        ret = omap3isp_video_init(&res->video_out, "resizer");
1746        if (ret < 0)
1747                goto error_video_out;
1748
1749        res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
1750
1751        /* Connect the video nodes to the resizer subdev. */
1752        ret = media_entity_create_link(&res->video_in.video.entity, 0,
1753                        &res->subdev.entity, RESZ_PAD_SINK, 0);
1754        if (ret < 0)
1755                goto error_link;
1756
1757        ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1758                        &res->video_out.video.entity, 0, 0);
1759        if (ret < 0)
1760                goto error_link;
1761
1762        return 0;
1763
1764error_link:
1765        omap3isp_video_cleanup(&res->video_out);
1766error_video_out:
1767        omap3isp_video_cleanup(&res->video_in);
1768error_video_in:
1769        media_entity_cleanup(&res->subdev.entity);
1770        return ret;
1771}
1772
1773/*
1774 * isp_resizer_init - Resizer initialization.
1775 * @isp : Pointer to ISP device
1776 * return -ENOMEM or zero on success
1777 */
1778int omap3isp_resizer_init(struct isp_device *isp)
1779{
1780        struct isp_res_device *res = &isp->isp_res;
1781
1782        init_waitqueue_head(&res->wait);
1783        atomic_set(&res->stopping, 0);
1784        return resizer_init_entities(res);
1785}
1786
1787void omap3isp_resizer_cleanup(struct isp_device *isp)
1788{
1789        struct isp_res_device *res = &isp->isp_res;
1790
1791        omap3isp_video_cleanup(&res->video_in);
1792        omap3isp_video_cleanup(&res->video_out);
1793        media_entity_cleanup(&res->subdev.entity);
1794}
1795