Linux Audio

Check our new training course

Loading...
   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_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_SUBDEV_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_SUBDEV_SEL_TGT_CROP_ACTUAL:
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_SUBDEV_SEL_TGT_CROP_ACTUAL ||
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
1535/*
1536 * resizer_init_formats - Initialize formats on all pads
1537 * @sd: ISP resizer V4L2 subdevice
1538 * @fh: V4L2 subdev file handle
1539 *
1540 * Initialize all pad formats with default values. If fh is not NULL, try
1541 * formats are initialized on the file handle. Otherwise active formats are
1542 * initialized on the device.
1543 */
1544static int resizer_init_formats(struct v4l2_subdev *sd,
1545				struct v4l2_subdev_fh *fh)
1546{
1547	struct v4l2_subdev_format format;
1548
1549	memset(&format, 0, sizeof(format));
1550	format.pad = RESZ_PAD_SINK;
1551	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1552	format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1553	format.format.width = 4096;
1554	format.format.height = 4096;
1555	resizer_set_format(sd, fh, &format);
1556
1557	return 0;
1558}
1559
1560/* subdev video operations */
1561static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1562	.s_stream = resizer_set_stream,
1563};
1564
1565/* subdev pad operations */
1566static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1567	.enum_mbus_code = resizer_enum_mbus_code,
1568	.enum_frame_size = resizer_enum_frame_size,
1569	.get_fmt = resizer_get_format,
1570	.set_fmt = resizer_set_format,
1571	.get_selection = resizer_get_selection,
1572	.set_selection = resizer_set_selection,
1573};
1574
1575/* subdev operations */
1576static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1577	.video = &resizer_v4l2_video_ops,
1578	.pad = &resizer_v4l2_pad_ops,
1579};
1580
1581/* subdev internal operations */
1582static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1583	.open = resizer_init_formats,
1584};
1585
1586/* -----------------------------------------------------------------------------
1587 * Media entity operations
1588 */
1589
1590/*
1591 * resizer_link_setup - Setup resizer connections.
1592 * @entity : Pointer to media entity structure
1593 * @local  : Pointer to local pad array
1594 * @remote : Pointer to remote pad array
1595 * @flags  : Link flags
1596 * return -EINVAL or zero on success
1597 */
1598static int resizer_link_setup(struct media_entity *entity,
1599			      const struct media_pad *local,
1600			      const struct media_pad *remote, u32 flags)
1601{
1602	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1603	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1604
1605	switch (local->index | media_entity_type(remote->entity)) {
1606	case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1607		/* read from memory */
1608		if (flags & MEDIA_LNK_FL_ENABLED) {
1609			if (res->input == RESIZER_INPUT_VP)
1610				return -EBUSY;
1611			res->input = RESIZER_INPUT_MEMORY;
1612		} else {
1613			if (res->input == RESIZER_INPUT_MEMORY)
1614				res->input = RESIZER_INPUT_NONE;
1615		}
1616		break;
1617
1618	case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1619		/* read from ccdc or previewer */
1620		if (flags & MEDIA_LNK_FL_ENABLED) {
1621			if (res->input == RESIZER_INPUT_MEMORY)
1622				return -EBUSY;
1623			res->input = RESIZER_INPUT_VP;
1624		} else {
1625			if (res->input == RESIZER_INPUT_VP)
1626				res->input = RESIZER_INPUT_NONE;
1627		}
1628		break;
1629
1630	case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1631		/* resizer always write to memory */
1632		break;
1633
1634	default:
1635		return -EINVAL;
1636	}
1637
1638	return 0;
1639}
1640
1641/* media operations */
1642static const struct media_entity_operations resizer_media_ops = {
1643	.link_setup = resizer_link_setup,
1644	.link_validate = v4l2_subdev_link_validate,
1645};
1646
1647void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1648{
1649	v4l2_device_unregister_subdev(&res->subdev);
1650	omap3isp_video_unregister(&res->video_in);
1651	omap3isp_video_unregister(&res->video_out);
1652}
1653
1654int omap3isp_resizer_register_entities(struct isp_res_device *res,
1655				       struct v4l2_device *vdev)
1656{
1657	int ret;
1658
1659	/* Register the subdev and video nodes. */
1660	ret = v4l2_device_register_subdev(vdev, &res->subdev);
1661	if (ret < 0)
1662		goto error;
1663
1664	ret = omap3isp_video_register(&res->video_in, vdev);
1665	if (ret < 0)
1666		goto error;
1667
1668	ret = omap3isp_video_register(&res->video_out, vdev);
1669	if (ret < 0)
1670		goto error;
1671
1672	return 0;
1673
1674error:
1675	omap3isp_resizer_unregister_entities(res);
1676	return ret;
1677}
1678
1679/* -----------------------------------------------------------------------------
1680 * ISP resizer initialization and cleanup
1681 */
1682
1683/*
1684 * resizer_init_entities - Initialize resizer subdev and media entity.
1685 * @res : Pointer to resizer device structure
1686 * return -ENOMEM or zero on success
1687 */
1688static int resizer_init_entities(struct isp_res_device *res)
1689{
1690	struct v4l2_subdev *sd = &res->subdev;
1691	struct media_pad *pads = res->pads;
1692	struct media_entity *me = &sd->entity;
1693	int ret;
1694
1695	res->input = RESIZER_INPUT_NONE;
1696
1697	v4l2_subdev_init(sd, &resizer_v4l2_ops);
1698	sd->internal_ops = &resizer_v4l2_internal_ops;
1699	strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1700	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
1701	v4l2_set_subdevdata(sd, res);
1702	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1703
1704	pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1705	pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1706
1707	me->ops = &resizer_media_ops;
1708	ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1709	if (ret < 0)
1710		return ret;
1711
1712	resizer_init_formats(sd, NULL);
1713
1714	res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1715	res->video_in.ops = &resizer_video_ops;
1716	res->video_in.isp = to_isp_device(res);
1717	res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1718	res->video_in.bpl_alignment = 32;
1719	res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1720	res->video_out.ops = &resizer_video_ops;
1721	res->video_out.isp = to_isp_device(res);
1722	res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1723	res->video_out.bpl_alignment = 32;
1724
1725	ret = omap3isp_video_init(&res->video_in, "resizer");
1726	if (ret < 0)
1727		goto error_video_in;
1728
1729	ret = omap3isp_video_init(&res->video_out, "resizer");
1730	if (ret < 0)
1731		goto error_video_out;
1732
1733	/* Connect the video nodes to the resizer subdev. */
1734	ret = media_entity_create_link(&res->video_in.video.entity, 0,
1735			&res->subdev.entity, RESZ_PAD_SINK, 0);
1736	if (ret < 0)
1737		goto error_link;
1738
1739	ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1740			&res->video_out.video.entity, 0, 0);
1741	if (ret < 0)
1742		goto error_link;
1743
1744	return 0;
1745
1746error_link:
1747	omap3isp_video_cleanup(&res->video_out);
1748error_video_out:
1749	omap3isp_video_cleanup(&res->video_in);
1750error_video_in:
1751	media_entity_cleanup(&res->subdev.entity);
1752	return ret;
1753}
1754
1755/*
1756 * isp_resizer_init - Resizer initialization.
1757 * @isp : Pointer to ISP device
1758 * return -ENOMEM or zero on success
1759 */
1760int omap3isp_resizer_init(struct isp_device *isp)
1761{
1762	struct isp_res_device *res = &isp->isp_res;
1763
1764	init_waitqueue_head(&res->wait);
1765	atomic_set(&res->stopping, 0);
1766	return resizer_init_entities(res);
1767}
1768
1769void omap3isp_resizer_cleanup(struct isp_device *isp)
1770{
1771	struct isp_res_device *res = &isp->isp_res;
1772
1773	omap3isp_video_cleanup(&res->video_in);
1774	omap3isp_video_cleanup(&res->video_out);
1775	media_entity_cleanup(&res->subdev.entity);
1776}