File Index
Files and directories
Sign in
FILE

ispresizer.c

File preview with syntax highlighting.

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