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);
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_g_crop - handle get crop subdev operation
1192 * @sd : pointer to v4l2 subdev structure
1193 * @pad : subdev pad
1194 * @crop : pointer to crop structure
1195 * @which : active or try format
1196 * return zero
1197 */
1198static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1199                          struct v4l2_subdev_crop *crop)
1200{
1201        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1202        struct v4l2_mbus_framefmt *format;
1203        struct resizer_ratio ratio;
1204
1205        /* Only sink pad has crop capability */
1206        if (crop->pad != RESZ_PAD_SINK)
1207                return -EINVAL;
1208
1209        format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1210        crop->rect = *__resizer_get_crop(res, fh, crop->which);
1211        resizer_calc_ratios(res, &crop->rect, format, &ratio);
1212
1213        return 0;
1214}
1215
1216/*
1217 * resizer_try_crop - mangles crop parameters.
1218 */
1219static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1220                             const struct v4l2_mbus_framefmt *source,
1221                             struct v4l2_rect *crop)
1222{
1223        const unsigned int spv = DEFAULT_PHASE;
1224        const unsigned int sph = DEFAULT_PHASE;
1225
1226        /* Crop rectangle is constrained to the output size so that zoom ratio
1227         * cannot exceed +/-4.0.
1228         */
1229        unsigned int min_width =
1230                ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1231        unsigned int min_height =
1232                ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1233        unsigned int max_width =
1234                ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1235        unsigned int max_height =
1236                ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1237
1238        crop->width = clamp_t(u32, crop->width, min_width, max_width);
1239        crop->height = clamp_t(u32, crop->height, min_height, max_height);
1240
1241        /* Crop can not go beyond of the input rectangle */
1242        crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1243        crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1244                              sink->width - crop->left);
1245        crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1246        crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1247                               sink->height - crop->top);
1248}
1249
1250/*
1251 * resizer_s_crop - handle set crop subdev operation
1252 * @sd : pointer to v4l2 subdev structure
1253 * @pad : subdev pad
1254 * @crop : pointer to crop structure
1255 * @which : active or try format
1256 * return -EINVAL or zero when succeed
1257 */
1258static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1259                          struct v4l2_subdev_crop *crop)
1260{
1261        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1262        struct isp_device *isp = to_isp_device(res);
1263        struct v4l2_mbus_framefmt *format_sink, *format_source;
1264        struct resizer_ratio ratio;
1265
1266        /* Only sink pad has crop capability */
1267        if (crop->pad != RESZ_PAD_SINK)
1268                return -EINVAL;
1269
1270        format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1271                                           crop->which);
1272        format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1273                                             crop->which);
1274
1275        dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1276                crop->rect.left, crop->rect.top, crop->rect.width,
1277                crop->rect.height, crop->which);
1278
1279        dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1280                format_sink->width, format_sink->height,
1281                format_source->width, format_source->height);
1282
1283        resizer_try_crop(format_sink, format_source, &crop->rect);
1284        *__resizer_get_crop(res, fh, crop->which) = crop->rect;
1285        resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1286
1287        if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1288                return 0;
1289
1290        res->ratio = ratio;
1291        res->crop.active = crop->rect;
1292
1293        /*
1294         * s_crop can be called while streaming is on. In this case
1295         * the crop values will be set in the next IRQ.
1296         */
1297        if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1298                res->applycrop = 1;
1299
1300        return 0;
1301}
1302
1303/* resizer pixel formats */
1304static const unsigned int resizer_formats[] = {
1305        V4L2_MBUS_FMT_UYVY8_1X16,
1306        V4L2_MBUS_FMT_YUYV8_1X16,
1307};
1308
1309static unsigned int resizer_max_in_width(struct isp_res_device *res)
1310{
1311        struct isp_device *isp = to_isp_device(res);
1312
1313        if (res->input == RESIZER_INPUT_MEMORY) {
1314                return MAX_IN_WIDTH_MEMORY_MODE;
1315        } else {
1316                if (isp->revision == ISP_REVISION_1_0)
1317                        return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1318                else
1319                        return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1320        }
1321}
1322
1323/*
1324 * resizer_try_format - Handle try format by pad subdev method
1325 * @res   : ISP resizer device
1326 * @fh    : V4L2 subdev file handle
1327 * @pad   : pad num
1328 * @fmt   : pointer to v4l2 format structure
1329 * @which : wanted subdev format
1330 */
1331static void resizer_try_format(struct isp_res_device *res,
1332                               struct v4l2_subdev_fh *fh, unsigned int pad,
1333                               struct v4l2_mbus_framefmt *fmt,
1334                               enum v4l2_subdev_format_whence which)
1335{
1336        struct v4l2_mbus_framefmt *format;
1337        struct resizer_ratio ratio;
1338        struct v4l2_rect crop;
1339
1340        switch (pad) {
1341        case RESZ_PAD_SINK:
1342                if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1343                    fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1344                        fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1345
1346                fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1347                                     resizer_max_in_width(res));
1348                fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1349                                      MAX_IN_HEIGHT);
1350                break;
1351
1352        case RESZ_PAD_SOURCE:
1353                format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1354                fmt->code = format->code;
1355
1356                crop = *__resizer_get_crop(res, fh, which);
1357                resizer_calc_ratios(res, &crop, fmt, &ratio);
1358                break;
1359        }
1360
1361        fmt->colorspace = V4L2_COLORSPACE_JPEG;
1362        fmt->field = V4L2_FIELD_NONE;
1363}
1364
1365/*
1366 * resizer_enum_mbus_code - Handle pixel format enumeration
1367 * @sd     : pointer to v4l2 subdev structure
1368 * @fh     : V4L2 subdev file handle
1369 * @code   : pointer to v4l2_subdev_mbus_code_enum structure
1370 * return -EINVAL or zero on success
1371 */
1372static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1373                                  struct v4l2_subdev_fh *fh,
1374                                  struct v4l2_subdev_mbus_code_enum *code)
1375{
1376        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1377        struct v4l2_mbus_framefmt *format;
1378
1379        if (code->pad == RESZ_PAD_SINK) {
1380                if (code->index >= ARRAY_SIZE(resizer_formats))
1381                        return -EINVAL;
1382
1383                code->code = resizer_formats[code->index];
1384        } else {
1385                if (code->index != 0)
1386                        return -EINVAL;
1387
1388                format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1389                                              V4L2_SUBDEV_FORMAT_TRY);
1390                code->code = format->code;
1391        }
1392
1393        return 0;
1394}
1395
1396static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1397                                   struct v4l2_subdev_fh *fh,
1398                                   struct v4l2_subdev_frame_size_enum *fse)
1399{
1400        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1401        struct v4l2_mbus_framefmt format;
1402
1403        if (fse->index != 0)
1404                return -EINVAL;
1405
1406        format.code = fse->code;
1407        format.width = 1;
1408        format.height = 1;
1409        resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1410        fse->min_width = format.width;
1411        fse->min_height = format.height;
1412
1413        if (format.code != fse->code)
1414                return -EINVAL;
1415
1416        format.code = fse->code;
1417        format.width = -1;
1418        format.height = -1;
1419        resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1420        fse->max_width = format.width;
1421        fse->max_height = format.height;
1422
1423        return 0;
1424}
1425
1426/*
1427 * resizer_get_format - Handle get format by pads subdev method
1428 * @sd    : pointer to v4l2 subdev structure
1429 * @fh    : V4L2 subdev file handle
1430 * @fmt   : pointer to v4l2 subdev format structure
1431 * return -EINVAL or zero on success
1432 */
1433static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1434                              struct v4l2_subdev_format *fmt)
1435{
1436        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1437        struct v4l2_mbus_framefmt *format;
1438
1439        format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1440        if (format == NULL)
1441                return -EINVAL;
1442
1443        fmt->format = *format;
1444        return 0;
1445}
1446
1447/*
1448 * resizer_set_format - Handle set format by pads subdev method
1449 * @sd    : pointer to v4l2 subdev structure
1450 * @fh    : V4L2 subdev file handle
1451 * @fmt   : pointer to v4l2 subdev format structure
1452 * return -EINVAL or zero on success
1453 */
1454static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1455                              struct v4l2_subdev_format *fmt)
1456{
1457        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1458        struct v4l2_mbus_framefmt *format;
1459        struct v4l2_rect *crop;
1460
1461        format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1462        if (format == NULL)
1463                return -EINVAL;
1464
1465        resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1466        *format = fmt->format;
1467
1468        if (fmt->pad == RESZ_PAD_SINK) {
1469                /* reset crop rectangle */
1470                crop = __resizer_get_crop(res, fh, fmt->which);
1471                crop->left = 0;
1472                crop->top = 0;
1473                crop->width = fmt->format.width;
1474                crop->height = fmt->format.height;
1475
1476                /* Propagate the format from sink to source */
1477                format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1478                                              fmt->which);
1479                *format = fmt->format;
1480                resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1481                                   fmt->which);
1482        }
1483
1484        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1485                /* Compute and store the active crop rectangle and resizer
1486                 * ratios. format already points to the source pad active
1487                 * format.
1488                 */
1489                res->crop.active = res->crop.request;
1490                resizer_calc_ratios(res, &res->crop.active, format,
1491                                       &res->ratio);
1492        }
1493
1494        return 0;
1495}
1496
1497/*
1498 * resizer_init_formats - Initialize formats on all pads
1499 * @sd: ISP resizer V4L2 subdevice
1500 * @fh: V4L2 subdev file handle
1501 *
1502 * Initialize all pad formats with default values. If fh is not NULL, try
1503 * formats are initialized on the file handle. Otherwise active formats are
1504 * initialized on the device.
1505 */
1506static int resizer_init_formats(struct v4l2_subdev *sd,
1507                                struct v4l2_subdev_fh *fh)
1508{
1509        struct v4l2_subdev_format format;
1510
1511        memset(&format, 0, sizeof(format));
1512        format.pad = RESZ_PAD_SINK;
1513        format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1514        format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1515        format.format.width = 4096;
1516        format.format.height = 4096;
1517        resizer_set_format(sd, fh, &format);
1518
1519        return 0;
1520}
1521
1522/* subdev video operations */
1523static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1524        .s_stream = resizer_set_stream,
1525};
1526
1527/* subdev pad operations */
1528static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1529        .enum_mbus_code = resizer_enum_mbus_code,
1530        .enum_frame_size = resizer_enum_frame_size,
1531        .get_fmt = resizer_get_format,
1532        .set_fmt = resizer_set_format,
1533        .get_crop = resizer_g_crop,
1534        .set_crop = resizer_s_crop,
1535};
1536
1537/* subdev operations */
1538static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1539        .video = &resizer_v4l2_video_ops,
1540        .pad = &resizer_v4l2_pad_ops,
1541};
1542
1543/* subdev internal operations */
1544static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1545        .open = resizer_init_formats,
1546};
1547
1548/* -----------------------------------------------------------------------------
1549 * Media entity operations
1550 */
1551
1552/*
1553 * resizer_link_setup - Setup resizer connections.
1554 * @entity : Pointer to media entity structure
1555 * @local  : Pointer to local pad array
1556 * @remote : Pointer to remote pad array
1557 * @flags  : Link flags
1558 * return -EINVAL or zero on success
1559 */
1560static int resizer_link_setup(struct media_entity *entity,
1561                              const struct media_pad *local,
1562                              const struct media_pad *remote, u32 flags)
1563{
1564        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1565        struct isp_res_device *res = v4l2_get_subdevdata(sd);
1566
1567        switch (local->index | media_entity_type(remote->entity)) {
1568        case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1569                /* read from memory */
1570                if (flags & MEDIA_LNK_FL_ENABLED) {
1571                        if (res->input == RESIZER_INPUT_VP)
1572                                return -EBUSY;
1573                        res->input = RESIZER_INPUT_MEMORY;
1574                } else {
1575                        if (res->input == RESIZER_INPUT_MEMORY)
1576                                res->input = RESIZER_INPUT_NONE;
1577                }
1578                break;
1579
1580        case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1581                /* read from ccdc or previewer */
1582                if (flags & MEDIA_LNK_FL_ENABLED) {
1583                        if (res->input == RESIZER_INPUT_MEMORY)
1584                                return -EBUSY;
1585                        res->input = RESIZER_INPUT_VP;
1586                } else {
1587                        if (res->input == RESIZER_INPUT_VP)
1588                                res->input = RESIZER_INPUT_NONE;
1589                }
1590                break;
1591
1592        case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1593                /* resizer always write to memory */
1594                break;
1595
1596        default:
1597                return -EINVAL;
1598        }
1599
1600        return 0;
1601}
1602
1603/* media operations */
1604static const struct media_entity_operations resizer_media_ops = {
1605        .link_setup = resizer_link_setup,
1606};
1607
1608void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1609{
1610        v4l2_device_unregister_subdev(&res->subdev);
1611        omap3isp_video_unregister(&res->video_in);
1612        omap3isp_video_unregister(&res->video_out);
1613}
1614
1615int omap3isp_resizer_register_entities(struct isp_res_device *res,
1616                                       struct v4l2_device *vdev)
1617{
1618        int ret;
1619
1620        /* Register the subdev and video nodes. */
1621        ret = v4l2_device_register_subdev(vdev, &res->subdev);
1622        if (ret < 0)
1623                goto error;
1624
1625        ret = omap3isp_video_register(&res->video_in, vdev);
1626        if (ret < 0)
1627                goto error;
1628
1629        ret = omap3isp_video_register(&res->video_out, vdev);
1630        if (ret < 0)
1631                goto error;
1632
1633        return 0;
1634
1635error:
1636        omap3isp_resizer_unregister_entities(res);
1637        return ret;
1638}
1639
1640/* -----------------------------------------------------------------------------
1641 * ISP resizer initialization and cleanup
1642 */
1643
1644/*
1645 * resizer_init_entities - Initialize resizer subdev and media entity.
1646 * @res : Pointer to resizer device structure
1647 * return -ENOMEM or zero on success
1648 */
1649static int resizer_init_entities(struct isp_res_device *res)
1650{
1651        struct v4l2_subdev *sd = &res->subdev;
1652        struct media_pad *pads = res->pads;
1653        struct media_entity *me = &sd->entity;
1654        int ret;
1655
1656        res->input = RESIZER_INPUT_NONE;
1657
1658        v4l2_subdev_init(sd, &resizer_v4l2_ops);
1659        sd->internal_ops = &resizer_v4l2_internal_ops;
1660        strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1661        sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
1662        v4l2_set_subdevdata(sd, res);
1663        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1664
1665        pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1666        pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1667
1668        me->ops = &resizer_media_ops;
1669        ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1670        if (ret < 0)
1671                return ret;
1672
1673        resizer_init_formats(sd, NULL);
1674
1675        res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1676        res->video_in.ops = &resizer_video_ops;
1677        res->video_in.isp = to_isp_device(res);
1678        res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1679        res->video_in.bpl_alignment = 32;
1680        res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1681        res->video_out.ops = &resizer_video_ops;
1682        res->video_out.isp = to_isp_device(res);
1683        res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1684        res->video_out.bpl_alignment = 32;
1685
1686        ret = omap3isp_video_init(&res->video_in, "resizer");
1687        if (ret < 0)
1688                goto error_video_in;
1689
1690        ret = omap3isp_video_init(&res->video_out, "resizer");
1691        if (ret < 0)
1692                goto error_video_out;
1693
1694        /* Connect the video nodes to the resizer subdev. */
1695        ret = media_entity_create_link(&res->video_in.video.entity, 0,
1696                        &res->subdev.entity, RESZ_PAD_SINK, 0);
1697        if (ret < 0)
1698                goto error_link;
1699
1700        ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1701                        &res->video_out.video.entity, 0, 0);
1702        if (ret < 0)
1703                goto error_link;
1704
1705        return 0;
1706
1707error_link:
1708        omap3isp_video_cleanup(&res->video_out);
1709error_video_out:
1710        omap3isp_video_cleanup(&res->video_in);
1711error_video_in:
1712        media_entity_cleanup(&res->subdev.entity);
1713        return ret;
1714}
1715
1716/*
1717 * isp_resizer_init - Resizer initialization.
1718 * @isp : Pointer to ISP device
1719 * return -ENOMEM or zero on success
1720 */
1721int omap3isp_resizer_init(struct isp_device *isp)
1722{
1723        struct isp_res_device *res = &isp->isp_res;
1724
1725        init_waitqueue_head(&res->wait);
1726        atomic_set(&res->stopping, 0);
1727        return resizer_init_entities(res);
1728}
1729
1730void omap3isp_resizer_cleanup(struct isp_device *isp)
1731{
1732        struct isp_res_device *res = &isp->isp_res;
1733
1734        omap3isp_video_cleanup(&res->video_in);
1735        omap3isp_video_cleanup(&res->video_out);
1736        media_entity_cleanup(&res->subdev.entity);
1737}
1738
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.