4 * TI OMAP3 ISP - Resizer module
6 * Copyright (C) 2010 Nokia Corporation
7 * Copyright (C) 2009 Texas Instruments, Inc
9 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10 * Sakari Ailus <sakari.ailus@iki.fi>
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.
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.
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
27 #include <linux/device.h>
29 #include <linux/module.h>
33 #include "ispresizer.h"
38 #define MIN_RESIZE_VALUE 64
39 #define MID_RESIZE_VALUE 512
40 #define MAX_RESIZE_VALUE 1024
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
49 #define MIN_OUT_WIDTH 16
50 #define MIN_OUT_HEIGHT 2
51 #define MAX_OUT_HEIGHT 4095
54 * Resizer Use Constraints
55 * "TRM ES3.1, table 12-46"
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
65 * Constants for ratio calculation
67 #define RESIZE_DIVISOR 256
68 #define DEFAULT_PHASE 1
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.
76 static const struct isprsz_coef filter_coefs = {
77 /* For 8-phase 4-tap horizontal filter: */
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
88 /* For 8-phase 4-tap vertical filter: */
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
99 /* For 4-phase 7-tap horizontal filter: */
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
107 /* For 4-phase 7-tap vertical filter: */
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
115 * The dummy padding is required in 7-tap mode because of how the
116 * registers are arranged physically.
122 * __resizer_get_format - helper function for getting resizer format
123 * @res : pointer to resizer private structure
125 * @fh : V4L2 subdev file handle
126 * @which : wanted subdev format
129 static 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)
133 if (which == V4L2_SUBDEV_FORMAT_TRY)
134 return v4l2_subdev_get_try_format(fh, pad);
136 return &res->formats[pad];
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
145 static struct v4l2_rect *
146 __resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
147 enum v4l2_subdev_format_whence which)
149 if (which == V4L2_SUBDEV_FORMAT_TRY)
150 return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
152 return &res->crop.request;
156 * resizer_set_filters - Set resizer filters
157 * @res: Device context.
158 * @h_coeff: horizontal coefficient
159 * @v_coeff: vertical coefficient
162 static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
165 struct isp_device *isp = to_isp_device(res);
166 u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
169 startaddr_h = ISPRSZ_HFILT10;
170 startaddr_v = ISPRSZ_VFILT10;
172 for (i = 0; i < COEFF_CNT; i += 2) {
174 (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
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);
185 * resizer_set_bilinear - Chrominance horizontal algorithm select
186 * @res: Device context.
187 * @type: Filtering interpolation type.
189 * Filtering that is same as luminance processing is
190 * intended only for downsampling, and bilinear interpolation
191 * is intended only for upsampling.
193 static void resizer_set_bilinear(struct isp_res_device *res,
194 enum resizer_chroma_algo type)
196 struct isp_device *isp = to_isp_device(res);
198 if (type == RSZ_BILINEAR)
199 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
202 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
207 * resizer_set_ycpos - Luminance and chrominance order
208 * @res: Device context.
209 * @order: order type.
211 static void resizer_set_ycpos(struct isp_res_device *res,
212 enum v4l2_mbus_pixelcode pixelcode)
214 struct isp_device *isp = to_isp_device(res);
217 case V4L2_MBUS_FMT_YUYV8_1X16:
218 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
221 case V4L2_MBUS_FMT_UYVY8_1X16:
222 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
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.
236 * Horizontal and vertical phase range is 0 to 7
238 static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
241 struct isp_device *isp = to_isp_device(res);
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;
249 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
253 * resizer_set_luma - Setup luminance enhancer parameters
254 * @res: Device context.
255 * @luma: Structure for luminance enhancer parameters.
259 * 0x1: [-1 2 -1]/2 high-pass filter
260 * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
263 * The data is coded in U4Q4 representation.
266 * The data is coded in U4Q4 representation.
269 * The data is coded in U8Q0 representation.
271 * The new luminance value is computed as:
272 * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
274 static void resizer_set_luma(struct isp_res_device *res,
275 struct resizer_luma_yenh *luma)
277 struct isp_device *isp = to_isp_device(res);
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;
289 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
293 * resizer_set_source - Input source select
294 * @res: Device context.
295 * @source: Input source type
297 * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
298 * Preview/CCDC engine, otherwise from memory.
300 static void resizer_set_source(struct isp_res_device *res,
301 enum resizer_input_entity source)
303 struct isp_device *isp = to_isp_device(res);
305 if (source == RESIZER_INPUT_MEMORY)
306 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
309 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
314 * resizer_set_ratio - Setup horizontal and vertical resizing value
315 * @res: Device context.
316 * @ratio: Structure for ratio parameters.
318 * Resizing range from 64 to 1024
320 static void resizer_set_ratio(struct isp_res_device *res,
321 const struct resizer_ratio *ratio)
323 struct isp_device *isp = to_isp_device(res);
324 const u16 *h_filter, *v_filter;
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);
335 /* prepare horizontal filter coefficients */
336 if (ratio->horz > MID_RESIZE_VALUE)
337 h_filter = &filter_coefs.h_filter_coef_7tap[0];
339 h_filter = &filter_coefs.h_filter_coef_4tap[0];
341 /* prepare vertical filter coefficients */
342 if (ratio->vert > MID_RESIZE_VALUE)
343 v_filter = &filter_coefs.v_filter_coef_7tap[0];
345 v_filter = &filter_coefs.v_filter_coef_4tap[0];
347 resizer_set_filters(res, h_filter, v_filter);
351 * resizer_set_dst_size - Setup the output height and width
352 * @res: Device context.
353 * @width: Output width.
354 * @height: Output height.
357 * The value must be EVEN.
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)
364 static void resizer_set_output_size(struct isp_res_device *res,
365 u32 width, u32 height)
367 struct isp_device *isp = to_isp_device(res);
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);
379 * resizer_set_output_offset - Setup memory offset for the output lines.
380 * @res: Device context.
381 * @offset: Memory offset.
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
387 static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
389 struct isp_device *isp = to_isp_device(res);
391 isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
395 * resizer_set_start - Setup vertical and horizontal start position
396 * @res: Device context.
397 * @left: Horizontal start position.
398 * @top: Vertical start position.
400 * Vertical start line:
401 * This field makes sense only when the resizer obtains its input
402 * from the preview engine/CCDC
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
409 static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
411 struct isp_device *isp = to_isp_device(res);
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;
419 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
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
428 static void resizer_set_input_size(struct isp_res_device *res,
429 u32 width, u32 height)
431 struct isp_device *isp = to_isp_device(res);
434 dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
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;
441 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
445 * resizer_set_src_offs - Setup the memory offset for the input lines
446 * @res: Device context.
447 * @offset: Memory offset.
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.
453 static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
455 struct isp_device *isp = to_isp_device(res);
457 isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
461 * resizer_set_intype - Input type select
462 * @res: Device context.
463 * @type: Pixel format type.
465 static void resizer_set_intype(struct isp_res_device *res,
466 enum resizer_colors_type type)
468 struct isp_device *isp = to_isp_device(res);
470 if (type == RSZ_COLOR8)
471 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
474 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
479 * __resizer_set_inaddr - Helper function for set input address
480 * @res : pointer to resizer private data structure
481 * @addr: input address
484 static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
486 struct isp_device *isp = to_isp_device(res);
488 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
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.
500 * The maximum data rate at the output of the horizontal resizer can thus be
503 * max intermediate rate <= L3 clock * input height / output height
504 * max intermediate rate <= L3 clock / 2
506 * The maximum data rate at the resizer input is then
508 * max input rate <= max intermediate rate * input width / output width
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.
514 void omap3isp_resizer_max_rate(struct isp_res_device *res,
515 unsigned int *max_rate)
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);
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);
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.
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
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
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
549 * request per second = data rate * 2 / 256
550 * cycles per request = cycles per second / requests per second
552 * The number of cycles per second is controlled by the L3 clock, leading to
554 * cycles per request = L3 frequency / 2 * 256 / data rate
556 static void resizer_adjust_bandwidth(struct isp_res_device *res)
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;
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);
576 switch (isp->revision) {
577 case ISP_REVISION_1_0:
578 case ISP_REVISION_2_0:
583 case ISP_REVISION_15_0:
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.
592 cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
594 minimum = DIV_ROUND_UP(cycles_per_request, granularity);
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
601 timeperframe = &pipe->max_timeperframe;
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;
609 maximum = cycles_per_request / granularity;
611 value = max(minimum, maximum);
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);
620 * omap3isp_resizer_busy - Checks if ISP resizer is busy.
622 * Returns busy field from ISPRSZ_PCR register.
624 int omap3isp_resizer_busy(struct isp_res_device *res)
626 struct isp_device *isp = to_isp_device(res);
628 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
633 * resizer_set_inaddr - Sets the memory address of the input frame.
634 * @addr: 32bit memory address aligned on 32byte boundary.
636 static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
638 res->addr_base = addr;
640 /* This will handle crop settings in stream off state */
641 if (res->crop_offset)
642 addr += res->crop_offset & ~0x1f;
644 __resizer_set_inaddr(res, addr);
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
653 static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
655 struct isp_device *isp = to_isp_device(res);
658 * Set output address. This needs to be in its own function
659 * because it changes often.
661 isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
662 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
666 * resizer_print_status - Prints the values of the resizer module registers.
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))
672 static void resizer_print_status(struct isp_res_device *res)
674 struct isp_device *isp = to_isp_device(res);
676 dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
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);
689 dev_dbg(isp->dev, "--------------------------------------------\n");
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
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.
705 * The input/output/ratio relationship is given by the OMAP34xx TRM:
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
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.
717 * Reverting the equations, we can compute the resizing ratios with
719 * - 8-phase, 4-tap mode
720 * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1)
721 * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1)
722 * - 4-phase, 7-tap mode
723 * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1)
724 * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1)
726 * The ratios are integer values, and must be rounded down to ensure that the
727 * cropped input size is not bigger than the uncropped input size. As the ratio
728 * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the
729 * 7-tap mode equations to compute a ratio approximation.
731 * We first clamp the output size according to the hardware capabilitie to avoid
732 * auto-cropping the input more than required to satisfy the TRM equations. The
733 * minimum output size is achieved with a scaling factor of 1024. It is thus
734 * computed using the 7-tap equations.
736 * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
737 * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
739 * Similarly, the maximum output size is achieved with a scaling factor of 64
740 * and computed using the 4-tap equations.
742 * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
743 * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
745 * The additional +255 term compensates for the round down operation performed
746 * by the TRM equations when shifting the value right by 8 bits.
748 * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
749 * the maximum value guarantees that the ratio value will never be smaller than
750 * the minimum, but it could still slightly exceed the maximum. Clamping the
751 * ratio will thus result in a resizing factor slightly larger than the
754 * To accommodate that, and make sure the TRM equations are satisfied exactly, we
755 * compute the input crop rectangle as the last step.
757 * As if the situation wasn't complex enough, the maximum output width depends
758 * on the vertical resizing ratio. Fortunately, the output height doesn't
759 * depend on the horizontal resizing ratio. We can then start by computing the
760 * output height and the vertical ratio, and then move to computing the output
761 * width and the horizontal ratio.
763 static void resizer_calc_ratios(struct isp_res_device *res,
764 struct v4l2_rect *input,
765 struct v4l2_mbus_framefmt *output,
766 struct resizer_ratio *ratio)
768 struct isp_device *isp = to_isp_device(res);
769 const unsigned int spv = DEFAULT_PHASE;
770 const unsigned int sph = DEFAULT_PHASE;
771 unsigned int upscaled_width;
772 unsigned int upscaled_height;
773 unsigned int min_width;
774 unsigned int min_height;
775 unsigned int max_width;
776 unsigned int max_height;
777 unsigned int width_alignment;
780 * Clamp the output height based on the hardware capabilities and
781 * compute the vertical resizing ratio.
783 min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
784 min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
785 max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
786 max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
787 output->height = clamp(output->height, min_height, max_height);
789 ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv)
790 / (output->height - 1);
791 ratio->vert = clamp_t(unsigned int, ratio->vert,
792 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
794 if (ratio->vert <= MID_RESIZE_VALUE) {
795 upscaled_height = (output->height - 1) * ratio->vert
797 input->height = (upscaled_height >> 8) + 4;
799 upscaled_height = (output->height - 1) * ratio->vert
801 input->height = (upscaled_height >> 8) + 7;
805 * Compute the minimum and maximum output widths based on the hardware
806 * capabilities. The maximum depends on the vertical resizing ratio.
808 min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
809 min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
811 if (ratio->vert <= MID_RESIZE_VALUE) {
812 switch (isp->revision) {
813 case ISP_REVISION_1_0:
814 max_width = MAX_4TAP_OUT_WIDTH_ES1;
817 case ISP_REVISION_2_0:
819 max_width = MAX_4TAP_OUT_WIDTH_ES2;
822 case ISP_REVISION_15_0:
823 max_width = MAX_4TAP_OUT_WIDTH_3630;
827 switch (isp->revision) {
828 case ISP_REVISION_1_0:
829 max_width = MAX_7TAP_OUT_WIDTH_ES1;
832 case ISP_REVISION_2_0:
834 max_width = MAX_7TAP_OUT_WIDTH_ES2;
837 case ISP_REVISION_15_0:
838 max_width = MAX_7TAP_OUT_WIDTH_3630;
842 max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
846 * The output width must be even, and must be a multiple of 16 bytes
847 * when upscaling vertically. Clamp the output width to the valid range.
848 * Take the alignment into account (the maximum width in 7-tap mode on
849 * ES2 isn't a multiple of 8) and align the result up to make sure it
850 * won't be smaller than the minimum.
852 width_alignment = ratio->vert < 256 ? 8 : 2;
853 output->width = clamp(output->width, min_width,
854 max_width & ~(width_alignment - 1));
855 output->width = ALIGN(output->width, width_alignment);
857 ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph)
858 / (output->width - 1);
859 ratio->horz = clamp_t(unsigned int, ratio->horz,
860 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
862 if (ratio->horz <= MID_RESIZE_VALUE) {
863 upscaled_width = (output->width - 1) * ratio->horz
865 input->width = (upscaled_width >> 8) + 7;
867 upscaled_width = (output->width - 1) * ratio->horz
869 input->width = (upscaled_width >> 8) + 7;
874 * resizer_set_crop_params - Setup hardware with cropping parameters
875 * @res : resizer private structure
876 * @crop_rect : current crop rectangle
877 * @ratio : resizer ratios
880 static void resizer_set_crop_params(struct isp_res_device *res,
881 const struct v4l2_mbus_framefmt *input,
882 const struct v4l2_mbus_framefmt *output)
884 resizer_set_ratio(res, &res->ratio);
886 /* Set chrominance horizontal algorithm */
887 if (res->ratio.horz >= RESIZE_DIVISOR)
888 resizer_set_bilinear(res, RSZ_THE_SAME);
890 resizer_set_bilinear(res, RSZ_BILINEAR);
892 resizer_adjust_bandwidth(res);
894 if (res->input == RESIZER_INPUT_MEMORY) {
895 /* Calculate additional offset for crop */
896 res->crop_offset = (res->crop.active.top * input->width +
897 res->crop.active.left) * 2;
899 * Write lowest 4 bits of horizontal pixel offset (in pixels),
900 * vertical start must be 0.
902 resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
905 * Set start (read) address for cropping, in bytes.
906 * Lowest 5 bits must be zero.
908 __resizer_set_inaddr(res,
909 res->addr_base + (res->crop_offset & ~0x1f));
912 * Set vertical start line and horizontal starting pixel.
913 * If the input is from CCDC/PREV, horizontal start field is
914 * in bytes (twice number of pixels).
916 resizer_set_start(res, res->crop.active.left * 2,
917 res->crop.active.top);
918 /* Input address and offset must be 0 for preview/ccdc input */
919 __resizer_set_inaddr(res, 0);
920 resizer_set_input_offset(res, 0);
923 /* Set the input size */
924 resizer_set_input_size(res, res->crop.active.width,
925 res->crop.active.height);
928 static void resizer_configure(struct isp_res_device *res)
930 struct v4l2_mbus_framefmt *informat, *outformat;
931 struct resizer_luma_yenh luma = {0, 0, 0, 0};
933 resizer_set_source(res, res->input);
935 informat = &res->formats[RESZ_PAD_SINK];
936 outformat = &res->formats[RESZ_PAD_SOURCE];
939 if (res->input == RESIZER_INPUT_VP)
940 resizer_set_input_offset(res, 0);
942 resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
944 /* YUV422 interleaved, default phase, no luma enhancement */
945 resizer_set_intype(res, RSZ_YUV422);
946 resizer_set_ycpos(res, informat->code);
947 resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
948 resizer_set_luma(res, &luma);
950 /* RESZ_PAD_SOURCE */
951 resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
952 resizer_set_output_size(res, outformat->width, outformat->height);
954 resizer_set_crop_params(res, informat, outformat);
957 /* -----------------------------------------------------------------------------
961 static void resizer_enable_oneshot(struct isp_res_device *res)
963 struct isp_device *isp = to_isp_device(res);
965 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
966 ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
969 void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
972 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
973 * condition, the module was paused and now we have a buffer queued
974 * on the output again. Restart the pipeline if running in continuous
977 if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
978 res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
979 resizer_enable_oneshot(res);
980 isp_video_dmaqueue_flags_clr(&res->video_out);
984 static void resizer_isr_buffer(struct isp_res_device *res)
986 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
987 struct isp_buffer *buffer;
990 if (res->state == ISP_PIPELINE_STREAM_STOPPED)
993 /* Complete the output buffer and, if reading from memory, the input
996 buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
997 if (buffer != NULL) {
998 resizer_set_outaddr(res, buffer->isp_addr);
1002 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1004 if (res->input == RESIZER_INPUT_MEMORY) {
1005 buffer = omap3isp_video_buffer_next(&res->video_in, 0);
1007 resizer_set_inaddr(res, buffer->isp_addr);
1008 pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1011 if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
1012 if (isp_pipeline_ready(pipe))
1013 omap3isp_pipeline_set_stream(pipe,
1014 ISP_PIPELINE_STREAM_SINGLESHOT);
1016 /* If an underrun occurs, the video queue operation handler will
1017 * restart the resizer. Otherwise restart it immediately.
1020 resizer_enable_oneshot(res);
1027 * omap3isp_resizer_isr - ISP resizer interrupt handler
1029 * Manage the resizer video buffers and configure shadowed and busy-locked
1032 void omap3isp_resizer_isr(struct isp_res_device *res)
1034 struct v4l2_mbus_framefmt *informat, *outformat;
1036 if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1039 if (res->applycrop) {
1040 outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1041 V4L2_SUBDEV_FORMAT_ACTIVE);
1042 informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1043 V4L2_SUBDEV_FORMAT_ACTIVE);
1044 resizer_set_crop_params(res, informat, outformat);
1048 resizer_isr_buffer(res);
1051 /* -----------------------------------------------------------------------------
1052 * ISP video operations
1055 static int resizer_video_queue(struct isp_video *video,
1056 struct isp_buffer *buffer)
1058 struct isp_res_device *res = &video->isp->isp_res;
1060 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1061 resizer_set_inaddr(res, buffer->isp_addr);
1064 * We now have a buffer queued on the output. Despite what the
1065 * TRM says, the resizer can't be restarted immediately.
1066 * Enabling it in one shot mode in the middle of a frame (or at
1067 * least asynchronously to the frame) results in the output
1068 * being shifted randomly left/right and up/down, as if the
1069 * hardware didn't synchronize itself to the beginning of the
1072 * Restart the resizer on the next sync interrupt if running in
1073 * continuous mode or when starting the stream.
1075 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1076 resizer_set_outaddr(res, buffer->isp_addr);
1081 static const struct isp_video_operations resizer_video_ops = {
1082 .queue = resizer_video_queue,
1085 /* -----------------------------------------------------------------------------
1086 * V4L2 subdev operations
1090 * resizer_set_stream - Enable/Disable streaming on resizer subdev
1091 * @sd: ISP resizer V4L2 subdev
1092 * @enable: 1 == Enable, 0 == Disable
1094 * The resizer hardware can't be enabled without a memory buffer to write to.
1095 * As the s_stream operation is called in response to a STREAMON call without
1096 * any buffer queued yet, just update the state field and return immediately.
1097 * The resizer will be enabled in resizer_video_queue().
1099 static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1101 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1102 struct isp_video *video_out = &res->video_out;
1103 struct isp_device *isp = to_isp_device(res);
1104 struct device *dev = to_device(res);
1106 if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1107 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1110 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1111 resizer_configure(res);
1113 resizer_print_status(res);
1117 case ISP_PIPELINE_STREAM_CONTINUOUS:
1118 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1119 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1120 resizer_enable_oneshot(res);
1121 isp_video_dmaqueue_flags_clr(video_out);
1125 case ISP_PIPELINE_STREAM_SINGLESHOT:
1126 if (res->input == RESIZER_INPUT_MEMORY)
1127 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1128 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1130 resizer_enable_oneshot(res);
1133 case ISP_PIPELINE_STREAM_STOPPED:
1134 if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1136 dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1137 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1138 OMAP3_ISP_SBL_RESIZER_WRITE);
1139 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1140 isp_video_dmaqueue_flags_clr(video_out);
1144 res->state = enable;
1149 * resizer_g_crop - handle get crop subdev operation
1150 * @sd : pointer to v4l2 subdev structure
1152 * @crop : pointer to crop structure
1153 * @which : active or try format
1156 static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1157 struct v4l2_subdev_crop *crop)
1159 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1160 struct v4l2_mbus_framefmt *format;
1161 struct resizer_ratio ratio;
1163 /* Only sink pad has crop capability */
1164 if (crop->pad != RESZ_PAD_SINK)
1167 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1168 crop->rect = *__resizer_get_crop(res, fh, crop->which);
1169 resizer_calc_ratios(res, &crop->rect, format, &ratio);
1175 * resizer_try_crop - mangles crop parameters.
1177 static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1178 const struct v4l2_mbus_framefmt *source,
1179 struct v4l2_rect *crop)
1181 const unsigned int spv = DEFAULT_PHASE;
1182 const unsigned int sph = DEFAULT_PHASE;
1184 /* Crop rectangle is constrained to the output size so that zoom ratio
1185 * cannot exceed +/-4.0.
1187 unsigned int min_width =
1188 ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1189 unsigned int min_height =
1190 ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1191 unsigned int max_width =
1192 ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1193 unsigned int max_height =
1194 ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1196 crop->width = clamp_t(u32, crop->width, min_width, max_width);
1197 crop->height = clamp_t(u32, crop->height, min_height, max_height);
1199 /* Crop can not go beyond of the input rectangle */
1200 crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1201 crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1202 sink->width - crop->left);
1203 crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1204 crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1205 sink->height - crop->top);
1209 * resizer_s_crop - handle set crop subdev operation
1210 * @sd : pointer to v4l2 subdev structure
1212 * @crop : pointer to crop structure
1213 * @which : active or try format
1214 * return -EINVAL or zero when succeed
1216 static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1217 struct v4l2_subdev_crop *crop)
1219 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1220 struct isp_device *isp = to_isp_device(res);
1221 struct v4l2_mbus_framefmt *format_sink, *format_source;
1222 struct resizer_ratio ratio;
1224 /* Only sink pad has crop capability */
1225 if (crop->pad != RESZ_PAD_SINK)
1228 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1230 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1233 dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1234 crop->rect.left, crop->rect.top, crop->rect.width,
1235 crop->rect.height, crop->which);
1237 dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1238 format_sink->width, format_sink->height,
1239 format_source->width, format_source->height);
1241 resizer_try_crop(format_sink, format_source, &crop->rect);
1242 *__resizer_get_crop(res, fh, crop->which) = crop->rect;
1243 resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1245 if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1249 res->crop.active = crop->rect;
1252 * s_crop can be called while streaming is on. In this case
1253 * the crop values will be set in the next IRQ.
1255 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1261 /* resizer pixel formats */
1262 static const unsigned int resizer_formats[] = {
1263 V4L2_MBUS_FMT_UYVY8_1X16,
1264 V4L2_MBUS_FMT_YUYV8_1X16,
1267 static unsigned int resizer_max_in_width(struct isp_res_device *res)
1269 struct isp_device *isp = to_isp_device(res);
1271 if (res->input == RESIZER_INPUT_MEMORY) {
1272 return MAX_IN_WIDTH_MEMORY_MODE;
1274 if (isp->revision == ISP_REVISION_1_0)
1275 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1277 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1282 * resizer_try_format - Handle try format by pad subdev method
1283 * @res : ISP resizer device
1284 * @fh : V4L2 subdev file handle
1286 * @fmt : pointer to v4l2 format structure
1287 * @which : wanted subdev format
1289 static void resizer_try_format(struct isp_res_device *res,
1290 struct v4l2_subdev_fh *fh, unsigned int pad,
1291 struct v4l2_mbus_framefmt *fmt,
1292 enum v4l2_subdev_format_whence which)
1294 struct v4l2_mbus_framefmt *format;
1295 struct resizer_ratio ratio;
1296 struct v4l2_rect crop;
1300 if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1301 fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1302 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1304 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1305 resizer_max_in_width(res));
1306 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1310 case RESZ_PAD_SOURCE:
1311 format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1312 fmt->code = format->code;
1314 crop = *__resizer_get_crop(res, fh, which);
1315 resizer_calc_ratios(res, &crop, fmt, &ratio);
1319 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1320 fmt->field = V4L2_FIELD_NONE;
1324 * resizer_enum_mbus_code - Handle pixel format enumeration
1325 * @sd : pointer to v4l2 subdev structure
1326 * @fh : V4L2 subdev file handle
1327 * @code : pointer to v4l2_subdev_mbus_code_enum structure
1328 * return -EINVAL or zero on success
1330 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1331 struct v4l2_subdev_fh *fh,
1332 struct v4l2_subdev_mbus_code_enum *code)
1334 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1335 struct v4l2_mbus_framefmt *format;
1337 if (code->pad == RESZ_PAD_SINK) {
1338 if (code->index >= ARRAY_SIZE(resizer_formats))
1341 code->code = resizer_formats[code->index];
1343 if (code->index != 0)
1346 format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1347 V4L2_SUBDEV_FORMAT_TRY);
1348 code->code = format->code;
1354 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1355 struct v4l2_subdev_fh *fh,
1356 struct v4l2_subdev_frame_size_enum *fse)
1358 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1359 struct v4l2_mbus_framefmt format;
1361 if (fse->index != 0)
1364 format.code = fse->code;
1367 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1368 fse->min_width = format.width;
1369 fse->min_height = format.height;
1371 if (format.code != fse->code)
1374 format.code = fse->code;
1377 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1378 fse->max_width = format.width;
1379 fse->max_height = format.height;
1385 * resizer_get_format - Handle get format by pads subdev method
1386 * @sd : pointer to v4l2 subdev structure
1387 * @fh : V4L2 subdev file handle
1388 * @fmt : pointer to v4l2 subdev format structure
1389 * return -EINVAL or zero on success
1391 static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1392 struct v4l2_subdev_format *fmt)
1394 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1395 struct v4l2_mbus_framefmt *format;
1397 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1401 fmt->format = *format;
1406 * resizer_set_format - Handle set format by pads subdev method
1407 * @sd : pointer to v4l2 subdev structure
1408 * @fh : V4L2 subdev file handle
1409 * @fmt : pointer to v4l2 subdev format structure
1410 * return -EINVAL or zero on success
1412 static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1413 struct v4l2_subdev_format *fmt)
1415 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1416 struct v4l2_mbus_framefmt *format;
1417 struct v4l2_rect *crop;
1419 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1423 resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1424 *format = fmt->format;
1426 if (fmt->pad == RESZ_PAD_SINK) {
1427 /* reset crop rectangle */
1428 crop = __resizer_get_crop(res, fh, fmt->which);
1431 crop->width = fmt->format.width;
1432 crop->height = fmt->format.height;
1434 /* Propagate the format from sink to source */
1435 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1437 *format = fmt->format;
1438 resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1442 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1443 /* Compute and store the active crop rectangle and resizer
1444 * ratios. format already points to the source pad active
1447 res->crop.active = res->crop.request;
1448 resizer_calc_ratios(res, &res->crop.active, format,
1456 * resizer_init_formats - Initialize formats on all pads
1457 * @sd: ISP resizer V4L2 subdevice
1458 * @fh: V4L2 subdev file handle
1460 * Initialize all pad formats with default values. If fh is not NULL, try
1461 * formats are initialized on the file handle. Otherwise active formats are
1462 * initialized on the device.
1464 static int resizer_init_formats(struct v4l2_subdev *sd,
1465 struct v4l2_subdev_fh *fh)
1467 struct v4l2_subdev_format format;
1469 memset(&format, 0, sizeof(format));
1470 format.pad = RESZ_PAD_SINK;
1471 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1472 format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1473 format.format.width = 4096;
1474 format.format.height = 4096;
1475 resizer_set_format(sd, fh, &format);
1480 /* subdev video operations */
1481 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1482 .s_stream = resizer_set_stream,
1485 /* subdev pad operations */
1486 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1487 .enum_mbus_code = resizer_enum_mbus_code,
1488 .enum_frame_size = resizer_enum_frame_size,
1489 .get_fmt = resizer_get_format,
1490 .set_fmt = resizer_set_format,
1491 .get_crop = resizer_g_crop,
1492 .set_crop = resizer_s_crop,
1495 /* subdev operations */
1496 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1497 .video = &resizer_v4l2_video_ops,
1498 .pad = &resizer_v4l2_pad_ops,
1501 /* subdev internal operations */
1502 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1503 .open = resizer_init_formats,
1506 /* -----------------------------------------------------------------------------
1507 * Media entity operations
1511 * resizer_link_setup - Setup resizer connections.
1512 * @entity : Pointer to media entity structure
1513 * @local : Pointer to local pad array
1514 * @remote : Pointer to remote pad array
1515 * @flags : Link flags
1516 * return -EINVAL or zero on success
1518 static int resizer_link_setup(struct media_entity *entity,
1519 const struct media_pad *local,
1520 const struct media_pad *remote, u32 flags)
1522 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1523 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1525 switch (local->index | media_entity_type(remote->entity)) {
1526 case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1527 /* read from memory */
1528 if (flags & MEDIA_LNK_FL_ENABLED) {
1529 if (res->input == RESIZER_INPUT_VP)
1531 res->input = RESIZER_INPUT_MEMORY;
1533 if (res->input == RESIZER_INPUT_MEMORY)
1534 res->input = RESIZER_INPUT_NONE;
1538 case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1539 /* read from ccdc or previewer */
1540 if (flags & MEDIA_LNK_FL_ENABLED) {
1541 if (res->input == RESIZER_INPUT_MEMORY)
1543 res->input = RESIZER_INPUT_VP;
1545 if (res->input == RESIZER_INPUT_VP)
1546 res->input = RESIZER_INPUT_NONE;
1550 case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1551 /* resizer always write to memory */
1561 /* media operations */
1562 static const struct media_entity_operations resizer_media_ops = {
1563 .link_setup = resizer_link_setup,
1567 * resizer_init_entities - Initialize resizer subdev and media entity.
1568 * @res : Pointer to resizer device structure
1569 * return -ENOMEM or zero on success
1571 static int resizer_init_entities(struct isp_res_device *res)
1573 struct v4l2_subdev *sd = &res->subdev;
1574 struct media_pad *pads = res->pads;
1575 struct media_entity *me = &sd->entity;
1578 res->input = RESIZER_INPUT_NONE;
1580 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1581 sd->internal_ops = &resizer_v4l2_internal_ops;
1582 strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1583 sd->grp_id = 1 << 16; /* group ID for isp subdevs */
1584 v4l2_set_subdevdata(sd, res);
1585 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1587 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1588 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1590 me->ops = &resizer_media_ops;
1591 ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1595 resizer_init_formats(sd, NULL);
1597 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1598 res->video_in.ops = &resizer_video_ops;
1599 res->video_in.isp = to_isp_device(res);
1600 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1601 res->video_in.bpl_alignment = 32;
1602 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1603 res->video_out.ops = &resizer_video_ops;
1604 res->video_out.isp = to_isp_device(res);
1605 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1606 res->video_out.bpl_alignment = 32;
1608 ret = omap3isp_video_init(&res->video_in, "resizer");
1612 ret = omap3isp_video_init(&res->video_out, "resizer");
1616 /* Connect the video nodes to the resizer subdev. */
1617 ret = media_entity_create_link(&res->video_in.video.entity, 0,
1618 &res->subdev.entity, RESZ_PAD_SINK, 0);
1622 ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1623 &res->video_out.video.entity, 0, 0);
1630 void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1632 media_entity_cleanup(&res->subdev.entity);
1634 v4l2_device_unregister_subdev(&res->subdev);
1635 omap3isp_video_unregister(&res->video_in);
1636 omap3isp_video_unregister(&res->video_out);
1639 int omap3isp_resizer_register_entities(struct isp_res_device *res,
1640 struct v4l2_device *vdev)
1644 /* Register the subdev and video nodes. */
1645 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1649 ret = omap3isp_video_register(&res->video_in, vdev);
1653 ret = omap3isp_video_register(&res->video_out, vdev);
1660 omap3isp_resizer_unregister_entities(res);
1664 /* -----------------------------------------------------------------------------
1665 * ISP resizer initialization and cleanup
1668 void omap3isp_resizer_cleanup(struct isp_device *isp)
1673 * isp_resizer_init - Resizer initialization.
1674 * @isp : Pointer to ISP device
1675 * return -ENOMEM or zero on success
1677 int omap3isp_resizer_init(struct isp_device *isp)
1679 struct isp_res_device *res = &isp->isp_res;
1682 init_waitqueue_head(&res->wait);
1683 atomic_set(&res->stopping, 0);
1684 ret = resizer_init_entities(res);
1690 omap3isp_resizer_cleanup(isp);