PM / sleep: Asynchronous threads for suspend_noirq
[linux/fpc-iii.git] / drivers / media / platform / omap3isp / ispresizer.c
blob0d36b8bc9f9806b1360d0a7482f2fe446fc70e4e
1 /*
2 * ispresizer.c
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
24 * 02110-1301 USA
27 #include <linux/device.h>
28 #include <linux/mm.h>
29 #include <linux/module.h>
31 #include "isp.h"
32 #include "ispreg.h"
33 #include "ispresizer.h"
36 * Resizer Constants
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: */
100 #define DUMMY 0
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.
118 #undef DUMMY
122 * __resizer_get_format - helper function for getting resizer format
123 * @res : pointer to resizer private structure
124 * @pad : pad number
125 * @fh : V4L2 subdev file handle
126 * @which : wanted subdev format
127 * return zero
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);
135 else
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);
151 else
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
160 * Return none
162 static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
163 const u16 *v_coeff)
165 struct isp_device *isp = to_isp_device(res);
166 u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
167 int i;
169 startaddr_h = ISPRSZ_HFILT10;
170 startaddr_v = ISPRSZ_VFILT10;
172 for (i = 0; i < COEFF_CNT; i += 2) {
173 tmp_h = h_coeff[i] |
174 (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
175 tmp_v = v_coeff[i] |
176 (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
177 isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
178 isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
179 startaddr_h += 4;
180 startaddr_v += 4;
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,
200 ISPRSZ_CNT_CBILIN);
201 else
202 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
203 ISPRSZ_CNT_CBILIN);
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);
216 switch (pixelcode) {
217 case V4L2_MBUS_FMT_YUYV8_1X16:
218 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
219 ISPRSZ_CNT_YCPOS);
220 break;
221 case V4L2_MBUS_FMT_UYVY8_1X16:
222 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
223 ISPRSZ_CNT_YCPOS);
224 break;
225 default:
226 return;
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,
239 u32 v_phase)
241 struct isp_device *isp = to_isp_device(res);
242 u32 rgval = 0;
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.
257 * Algorithm select:
258 * 0x0: Disable
259 * 0x1: [-1 2 -1]/2 high-pass filter
260 * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
262 * Maximum gain:
263 * The data is coded in U4Q4 representation.
265 * Slope:
266 * The data is coded in U4Q4 representation.
268 * Coring offset:
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);
278 u32 rgval = 0;
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,
307 ISPRSZ_CNT_INPSRC);
308 else
309 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
310 ISPRSZ_CNT_INPSRC);
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;
325 u32 rgval = 0;
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];
338 else
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];
344 else
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.
356 * Width :
357 * The value must be EVEN.
359 * Height:
360 * The number of bytes written to SDRAM must be
361 * a multiple of 16-bytes if the vertical resizing factor
362 * is greater than 1x (upsizing)
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);
368 u32 rgval = 0;
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);
412 u32 rgval = 0;
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);
432 u32 rgval = 0;
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,
472 ISPRSZ_CNT_INPTYP);
473 else
474 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
475 ISPRSZ_CNT_INPTYP);
479 * __resizer_set_inaddr - Helper function for set input address
480 * @res : pointer to resizer private data structure
481 * @addr: input address
482 * return none
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
501 * computed with
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);
520 unsigned long clock;
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
538 * process.
540 * For live image pipelines, the data rate is set by the frame format, size and
541 * rate. The sensor output frame rate must not exceed the maximum resizer data
542 * rate.
544 * The resizer slows down read requests by inserting wait cycles in the SBL
545 * requests. The maximum number of 256-byte requests per second can be computed
546 * as (the data rate is multiplied by 2 to convert from pixels per second to
547 * bytes per second)
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;
568 unsigned int value;
570 if (res->input != RESIZER_INPUT_MEMORY) {
571 isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
572 ISPSBL_SDR_REQ_RSZ_EXP_MASK);
573 return;
576 switch (isp->revision) {
577 case ISP_REVISION_1_0:
578 case ISP_REVISION_2_0:
579 default:
580 granularity = 1024;
581 break;
583 case ISP_REVISION_15_0:
584 granularity = 32;
585 break;
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,
593 pipe->max_rate);
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
599 * down.
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) &
629 ISPRSZ_PCR_BUSY;
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
651 * boundary.
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 calculating resizer ratios
694 * @res: pointer to resizer private data structure
695 * @input: input frame size
696 * @output: output frame size
697 * @ratio : return calculated ratios
698 * return none
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 * The equations can't be easily reverted, as the >> 8 operation is not linear.
718 * In addition, not all input sizes can be achieved for a given output size. To
719 * get the highest input size lower than or equal to the requested input size,
720 * we need to compute the highest resizing ratio that satisfies the following
721 * inequality (taking the 4-tap mode width equation as an example)
723 * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7
725 * (where iw is the requested input width) which can be rewritten as
727 * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8
728 * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b
729 * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16
731 * where b is the value of the 8 least significant bits of the right hand side
732 * expression of the last inequality. The highest resizing ratio value will be
733 * achieved when b is equal to its maximum value of 255. That resizing ratio
734 * value will still satisfy the original inequality, as b will disappear when
735 * the expression will be shifted right by 8.
737 * The reverted equations thus become
739 * - 8-phase, 4-tap mode
740 * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
741 * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1)
742 * - 4-phase, 7-tap mode
743 * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1)
744 * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1)
746 * The ratios are integer values, and are rounded down to ensure that the
747 * cropped input size is not bigger than the uncropped input size.
749 * As the number of phases/taps, used to select the correct equations to compute
750 * the ratio, depends on the ratio, we start with the 4-tap mode equations to
751 * compute an approximation of the ratio, and switch to the 7-tap mode equations
752 * if the approximation is higher than the ratio threshold.
754 * As the 7-tap mode equations will return a ratio smaller than or equal to the
755 * 4-tap mode equations, the resulting ratio could become lower than or equal to
756 * the ratio threshold. This 'equations loop' isn't an issue as long as the
757 * correct equations are used to compute the final input size. Starting with the
758 * 4-tap mode equations ensure that, in case of values resulting in a 'ratio
759 * loop', the smallest of the ratio values will be used, never exceeding the
760 * requested input size.
762 * We first clamp the output size according to the hardware capability to avoid
763 * auto-cropping the input more than required to satisfy the TRM equations. The
764 * minimum output size is achieved with a scaling factor of 1024. It is thus
765 * computed using the 7-tap equations.
767 * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
768 * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
770 * Similarly, the maximum output size is achieved with a scaling factor of 64
771 * and computed using the 4-tap equations.
773 * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
774 * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
776 * The additional +255 term compensates for the round down operation performed
777 * by the TRM equations when shifting the value right by 8 bits.
779 * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
780 * the maximum value guarantees that the ratio value will never be smaller than
781 * the minimum, but it could still slightly exceed the maximum. Clamping the
782 * ratio will thus result in a resizing factor slightly larger than the
783 * requested value.
785 * To accommodate that, and make sure the TRM equations are satisfied exactly, we
786 * compute the input crop rectangle as the last step.
788 * As if the situation wasn't complex enough, the maximum output width depends
789 * on the vertical resizing ratio. Fortunately, the output height doesn't
790 * depend on the horizontal resizing ratio. We can then start by computing the
791 * output height and the vertical ratio, and then move to computing the output
792 * width and the horizontal ratio.
794 static void resizer_calc_ratios(struct isp_res_device *res,
795 struct v4l2_rect *input,
796 struct v4l2_mbus_framefmt *output,
797 struct resizer_ratio *ratio)
799 struct isp_device *isp = to_isp_device(res);
800 const unsigned int spv = DEFAULT_PHASE;
801 const unsigned int sph = DEFAULT_PHASE;
802 unsigned int upscaled_width;
803 unsigned int upscaled_height;
804 unsigned int min_width;
805 unsigned int min_height;
806 unsigned int max_width;
807 unsigned int max_height;
808 unsigned int width_alignment;
809 unsigned int width;
810 unsigned int height;
813 * Clamp the output height based on the hardware capabilities and
814 * compute the vertical resizing ratio.
816 min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
817 min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
818 max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
819 max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
820 output->height = clamp(output->height, min_height, max_height);
822 ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
823 / (output->height - 1);
824 if (ratio->vert > MID_RESIZE_VALUE)
825 ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
826 / (output->height - 1);
827 ratio->vert = clamp_t(unsigned int, ratio->vert,
828 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
830 if (ratio->vert <= MID_RESIZE_VALUE) {
831 upscaled_height = (output->height - 1) * ratio->vert
832 + 32 * spv + 16;
833 height = (upscaled_height >> 8) + 4;
834 } else {
835 upscaled_height = (output->height - 1) * ratio->vert
836 + 64 * spv + 32;
837 height = (upscaled_height >> 8) + 7;
841 * Compute the minimum and maximum output widths based on the hardware
842 * capabilities. The maximum depends on the vertical resizing ratio.
844 min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
845 min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
847 if (ratio->vert <= MID_RESIZE_VALUE) {
848 switch (isp->revision) {
849 case ISP_REVISION_1_0:
850 max_width = MAX_4TAP_OUT_WIDTH_ES1;
851 break;
853 case ISP_REVISION_2_0:
854 default:
855 max_width = MAX_4TAP_OUT_WIDTH_ES2;
856 break;
858 case ISP_REVISION_15_0:
859 max_width = MAX_4TAP_OUT_WIDTH_3630;
860 break;
862 } else {
863 switch (isp->revision) {
864 case ISP_REVISION_1_0:
865 max_width = MAX_7TAP_OUT_WIDTH_ES1;
866 break;
868 case ISP_REVISION_2_0:
869 default:
870 max_width = MAX_7TAP_OUT_WIDTH_ES2;
871 break;
873 case ISP_REVISION_15_0:
874 max_width = MAX_7TAP_OUT_WIDTH_3630;
875 break;
878 max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
879 + 1, max_width);
882 * The output width must be even, and must be a multiple of 16 bytes
883 * when upscaling vertically. Clamp the output width to the valid range.
884 * Take the alignment into account (the maximum width in 7-tap mode on
885 * ES2 isn't a multiple of 8) and align the result up to make sure it
886 * won't be smaller than the minimum.
888 width_alignment = ratio->vert < 256 ? 8 : 2;
889 output->width = clamp(output->width, min_width,
890 max_width & ~(width_alignment - 1));
891 output->width = ALIGN(output->width, width_alignment);
893 ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
894 / (output->width - 1);
895 if (ratio->horz > MID_RESIZE_VALUE)
896 ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
897 / (output->width - 1);
898 ratio->horz = clamp_t(unsigned int, ratio->horz,
899 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
901 if (ratio->horz <= MID_RESIZE_VALUE) {
902 upscaled_width = (output->width - 1) * ratio->horz
903 + 32 * sph + 16;
904 width = (upscaled_width >> 8) + 7;
905 } else {
906 upscaled_width = (output->width - 1) * ratio->horz
907 + 64 * sph + 32;
908 width = (upscaled_width >> 8) + 7;
911 /* Center the new crop rectangle. */
912 input->left += (input->width - width) / 2;
913 input->top += (input->height - height) / 2;
914 input->width = width;
915 input->height = height;
919 * resizer_set_crop_params - Setup hardware with cropping parameters
920 * @res : resizer private structure
921 * @crop_rect : current crop rectangle
922 * @ratio : resizer ratios
923 * return none
925 static void resizer_set_crop_params(struct isp_res_device *res,
926 const struct v4l2_mbus_framefmt *input,
927 const struct v4l2_mbus_framefmt *output)
929 resizer_set_ratio(res, &res->ratio);
931 /* Set chrominance horizontal algorithm */
932 if (res->ratio.horz >= RESIZE_DIVISOR)
933 resizer_set_bilinear(res, RSZ_THE_SAME);
934 else
935 resizer_set_bilinear(res, RSZ_BILINEAR);
937 resizer_adjust_bandwidth(res);
939 if (res->input == RESIZER_INPUT_MEMORY) {
940 /* Calculate additional offset for crop */
941 res->crop_offset = (res->crop.active.top * input->width +
942 res->crop.active.left) * 2;
944 * Write lowest 4 bits of horizontal pixel offset (in pixels),
945 * vertical start must be 0.
947 resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
950 * Set start (read) address for cropping, in bytes.
951 * Lowest 5 bits must be zero.
953 __resizer_set_inaddr(res,
954 res->addr_base + (res->crop_offset & ~0x1f));
955 } else {
957 * Set vertical start line and horizontal starting pixel.
958 * If the input is from CCDC/PREV, horizontal start field is
959 * in bytes (twice number of pixels).
961 resizer_set_start(res, res->crop.active.left * 2,
962 res->crop.active.top);
963 /* Input address and offset must be 0 for preview/ccdc input */
964 __resizer_set_inaddr(res, 0);
965 resizer_set_input_offset(res, 0);
968 /* Set the input size */
969 resizer_set_input_size(res, res->crop.active.width,
970 res->crop.active.height);
973 static void resizer_configure(struct isp_res_device *res)
975 struct v4l2_mbus_framefmt *informat, *outformat;
976 struct resizer_luma_yenh luma = {0, 0, 0, 0};
978 resizer_set_source(res, res->input);
980 informat = &res->formats[RESZ_PAD_SINK];
981 outformat = &res->formats[RESZ_PAD_SOURCE];
983 /* RESZ_PAD_SINK */
984 if (res->input == RESIZER_INPUT_VP)
985 resizer_set_input_offset(res, 0);
986 else
987 resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
989 /* YUV422 interleaved, default phase, no luma enhancement */
990 resizer_set_intype(res, RSZ_YUV422);
991 resizer_set_ycpos(res, informat->code);
992 resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
993 resizer_set_luma(res, &luma);
995 /* RESZ_PAD_SOURCE */
996 resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
997 resizer_set_output_size(res, outformat->width, outformat->height);
999 resizer_set_crop_params(res, informat, outformat);
1002 /* -----------------------------------------------------------------------------
1003 * Interrupt handling
1006 static void resizer_enable_oneshot(struct isp_res_device *res)
1008 struct isp_device *isp = to_isp_device(res);
1010 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
1011 ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
1014 void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
1017 * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
1018 * condition, the module was paused and now we have a buffer queued
1019 * on the output again. Restart the pipeline if running in continuous
1020 * mode.
1022 if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
1023 res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1024 resizer_enable_oneshot(res);
1025 isp_video_dmaqueue_flags_clr(&res->video_out);
1029 static void resizer_isr_buffer(struct isp_res_device *res)
1031 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
1032 struct isp_buffer *buffer;
1033 int restart = 0;
1035 if (res->state == ISP_PIPELINE_STREAM_STOPPED)
1036 return;
1038 /* Complete the output buffer and, if reading from memory, the input
1039 * buffer.
1041 buffer = omap3isp_video_buffer_next(&res->video_out);
1042 if (buffer != NULL) {
1043 resizer_set_outaddr(res, buffer->isp_addr);
1044 restart = 1;
1047 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1049 if (res->input == RESIZER_INPUT_MEMORY) {
1050 buffer = omap3isp_video_buffer_next(&res->video_in);
1051 if (buffer != NULL)
1052 resizer_set_inaddr(res, buffer->isp_addr);
1053 pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1056 if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
1057 if (isp_pipeline_ready(pipe))
1058 omap3isp_pipeline_set_stream(pipe,
1059 ISP_PIPELINE_STREAM_SINGLESHOT);
1060 } else {
1061 /* If an underrun occurs, the video queue operation handler will
1062 * restart the resizer. Otherwise restart it immediately.
1064 if (restart)
1065 resizer_enable_oneshot(res);
1070 * omap3isp_resizer_isr - ISP resizer interrupt handler
1072 * Manage the resizer video buffers and configure shadowed and busy-locked
1073 * registers.
1075 void omap3isp_resizer_isr(struct isp_res_device *res)
1077 struct v4l2_mbus_framefmt *informat, *outformat;
1079 if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1080 return;
1082 if (res->applycrop) {
1083 outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1084 V4L2_SUBDEV_FORMAT_ACTIVE);
1085 informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1086 V4L2_SUBDEV_FORMAT_ACTIVE);
1087 resizer_set_crop_params(res, informat, outformat);
1088 res->applycrop = 0;
1091 resizer_isr_buffer(res);
1094 /* -----------------------------------------------------------------------------
1095 * ISP video operations
1098 static int resizer_video_queue(struct isp_video *video,
1099 struct isp_buffer *buffer)
1101 struct isp_res_device *res = &video->isp->isp_res;
1103 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1104 resizer_set_inaddr(res, buffer->isp_addr);
1107 * We now have a buffer queued on the output. Despite what the
1108 * TRM says, the resizer can't be restarted immediately.
1109 * Enabling it in one shot mode in the middle of a frame (or at
1110 * least asynchronously to the frame) results in the output
1111 * being shifted randomly left/right and up/down, as if the
1112 * hardware didn't synchronize itself to the beginning of the
1113 * frame correctly.
1115 * Restart the resizer on the next sync interrupt if running in
1116 * continuous mode or when starting the stream.
1118 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1119 resizer_set_outaddr(res, buffer->isp_addr);
1121 return 0;
1124 static const struct isp_video_operations resizer_video_ops = {
1125 .queue = resizer_video_queue,
1128 /* -----------------------------------------------------------------------------
1129 * V4L2 subdev operations
1133 * resizer_set_stream - Enable/Disable streaming on resizer subdev
1134 * @sd: ISP resizer V4L2 subdev
1135 * @enable: 1 == Enable, 0 == Disable
1137 * The resizer hardware can't be enabled without a memory buffer to write to.
1138 * As the s_stream operation is called in response to a STREAMON call without
1139 * any buffer queued yet, just update the state field and return immediately.
1140 * The resizer will be enabled in resizer_video_queue().
1142 static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1144 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1145 struct isp_video *video_out = &res->video_out;
1146 struct isp_device *isp = to_isp_device(res);
1147 struct device *dev = to_device(res);
1149 if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1150 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1151 return 0;
1153 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1154 resizer_configure(res);
1155 resizer_print_status(res);
1158 switch (enable) {
1159 case ISP_PIPELINE_STREAM_CONTINUOUS:
1160 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1161 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1162 resizer_enable_oneshot(res);
1163 isp_video_dmaqueue_flags_clr(video_out);
1165 break;
1167 case ISP_PIPELINE_STREAM_SINGLESHOT:
1168 if (res->input == RESIZER_INPUT_MEMORY)
1169 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1170 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1172 resizer_enable_oneshot(res);
1173 break;
1175 case ISP_PIPELINE_STREAM_STOPPED:
1176 if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1177 &res->stopping))
1178 dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1179 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1180 OMAP3_ISP_SBL_RESIZER_WRITE);
1181 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1182 isp_video_dmaqueue_flags_clr(video_out);
1183 break;
1186 res->state = enable;
1187 return 0;
1191 * resizer_try_crop - mangles crop parameters.
1193 static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1194 const struct v4l2_mbus_framefmt *source,
1195 struct v4l2_rect *crop)
1197 const unsigned int spv = DEFAULT_PHASE;
1198 const unsigned int sph = DEFAULT_PHASE;
1200 /* Crop rectangle is constrained by the output size so that zoom ratio
1201 * cannot exceed +/-4.0.
1203 unsigned int min_width =
1204 ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1205 unsigned int min_height =
1206 ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1207 unsigned int max_width =
1208 ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1209 unsigned int max_height =
1210 ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1212 crop->width = clamp_t(u32, crop->width, min_width, max_width);
1213 crop->height = clamp_t(u32, crop->height, min_height, max_height);
1215 /* Crop can not go beyond of the input rectangle */
1216 crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1217 crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1218 sink->width - crop->left);
1219 crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1220 crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1221 sink->height - crop->top);
1225 * resizer_get_selection - Retrieve a selection rectangle on a pad
1226 * @sd: ISP resizer V4L2 subdevice
1227 * @fh: V4L2 subdev file handle
1228 * @sel: Selection rectangle
1230 * The only supported rectangles are the crop rectangles on the sink pad.
1232 * Return 0 on success or a negative error code otherwise.
1234 static int resizer_get_selection(struct v4l2_subdev *sd,
1235 struct v4l2_subdev_fh *fh,
1236 struct v4l2_subdev_selection *sel)
1238 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1239 struct v4l2_mbus_framefmt *format_source;
1240 struct v4l2_mbus_framefmt *format_sink;
1241 struct resizer_ratio ratio;
1243 if (sel->pad != RESZ_PAD_SINK)
1244 return -EINVAL;
1246 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1247 sel->which);
1248 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1249 sel->which);
1251 switch (sel->target) {
1252 case V4L2_SEL_TGT_CROP_BOUNDS:
1253 sel->r.left = 0;
1254 sel->r.top = 0;
1255 sel->r.width = INT_MAX;
1256 sel->r.height = INT_MAX;
1258 resizer_try_crop(format_sink, format_source, &sel->r);
1259 resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1260 break;
1262 case V4L2_SEL_TGT_CROP:
1263 sel->r = *__resizer_get_crop(res, fh, sel->which);
1264 resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1265 break;
1267 default:
1268 return -EINVAL;
1271 return 0;
1275 * resizer_set_selection - Set a selection rectangle on a pad
1276 * @sd: ISP resizer V4L2 subdevice
1277 * @fh: V4L2 subdev file handle
1278 * @sel: Selection rectangle
1280 * The only supported rectangle is the actual crop rectangle on the sink pad.
1282 * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
1283 * was always set.
1285 * Return 0 on success or a negative error code otherwise.
1287 static int resizer_set_selection(struct v4l2_subdev *sd,
1288 struct v4l2_subdev_fh *fh,
1289 struct v4l2_subdev_selection *sel)
1291 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1292 struct isp_device *isp = to_isp_device(res);
1293 struct v4l2_mbus_framefmt *format_sink, *format_source;
1294 struct resizer_ratio ratio;
1296 if (sel->target != V4L2_SEL_TGT_CROP ||
1297 sel->pad != RESZ_PAD_SINK)
1298 return -EINVAL;
1300 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1301 sel->which);
1302 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1303 sel->which);
1305 dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1306 sel->r.left, sel->r.top, sel->r.width, sel->r.height,
1307 sel->which);
1309 dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1310 format_sink->width, format_sink->height,
1311 format_source->width, format_source->height);
1313 /* Clamp the crop rectangle to the bounds, and then mangle it further to
1314 * fulfill the TRM equations. Store the clamped but otherwise unmangled
1315 * rectangle to avoid cropping the input multiple times: when an
1316 * application sets the output format, the current crop rectangle is
1317 * mangled during crop rectangle computation, which would lead to a new,
1318 * smaller input crop rectangle every time the output size is set if we
1319 * stored the mangled rectangle.
1321 resizer_try_crop(format_sink, format_source, &sel->r);
1322 *__resizer_get_crop(res, fh, sel->which) = sel->r;
1323 resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1325 if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
1326 return 0;
1328 res->ratio = ratio;
1329 res->crop.active = sel->r;
1332 * set_selection can be called while streaming is on. In this case the
1333 * crop values will be set in the next IRQ.
1335 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1336 res->applycrop = 1;
1338 return 0;
1341 /* resizer pixel formats */
1342 static const unsigned int resizer_formats[] = {
1343 V4L2_MBUS_FMT_UYVY8_1X16,
1344 V4L2_MBUS_FMT_YUYV8_1X16,
1347 static unsigned int resizer_max_in_width(struct isp_res_device *res)
1349 struct isp_device *isp = to_isp_device(res);
1351 if (res->input == RESIZER_INPUT_MEMORY) {
1352 return MAX_IN_WIDTH_MEMORY_MODE;
1353 } else {
1354 if (isp->revision == ISP_REVISION_1_0)
1355 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1356 else
1357 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1362 * resizer_try_format - Handle try format by pad subdev method
1363 * @res : ISP resizer device
1364 * @fh : V4L2 subdev file handle
1365 * @pad : pad num
1366 * @fmt : pointer to v4l2 format structure
1367 * @which : wanted subdev format
1369 static void resizer_try_format(struct isp_res_device *res,
1370 struct v4l2_subdev_fh *fh, unsigned int pad,
1371 struct v4l2_mbus_framefmt *fmt,
1372 enum v4l2_subdev_format_whence which)
1374 struct v4l2_mbus_framefmt *format;
1375 struct resizer_ratio ratio;
1376 struct v4l2_rect crop;
1378 switch (pad) {
1379 case RESZ_PAD_SINK:
1380 if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1381 fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1382 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1384 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1385 resizer_max_in_width(res));
1386 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1387 MAX_IN_HEIGHT);
1388 break;
1390 case RESZ_PAD_SOURCE:
1391 format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1392 fmt->code = format->code;
1394 crop = *__resizer_get_crop(res, fh, which);
1395 resizer_calc_ratios(res, &crop, fmt, &ratio);
1396 break;
1399 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1400 fmt->field = V4L2_FIELD_NONE;
1404 * resizer_enum_mbus_code - Handle pixel format enumeration
1405 * @sd : pointer to v4l2 subdev structure
1406 * @fh : V4L2 subdev file handle
1407 * @code : pointer to v4l2_subdev_mbus_code_enum structure
1408 * return -EINVAL or zero on success
1410 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1411 struct v4l2_subdev_fh *fh,
1412 struct v4l2_subdev_mbus_code_enum *code)
1414 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1415 struct v4l2_mbus_framefmt *format;
1417 if (code->pad == RESZ_PAD_SINK) {
1418 if (code->index >= ARRAY_SIZE(resizer_formats))
1419 return -EINVAL;
1421 code->code = resizer_formats[code->index];
1422 } else {
1423 if (code->index != 0)
1424 return -EINVAL;
1426 format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1427 V4L2_SUBDEV_FORMAT_TRY);
1428 code->code = format->code;
1431 return 0;
1434 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1435 struct v4l2_subdev_fh *fh,
1436 struct v4l2_subdev_frame_size_enum *fse)
1438 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1439 struct v4l2_mbus_framefmt format;
1441 if (fse->index != 0)
1442 return -EINVAL;
1444 format.code = fse->code;
1445 format.width = 1;
1446 format.height = 1;
1447 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1448 fse->min_width = format.width;
1449 fse->min_height = format.height;
1451 if (format.code != fse->code)
1452 return -EINVAL;
1454 format.code = fse->code;
1455 format.width = -1;
1456 format.height = -1;
1457 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1458 fse->max_width = format.width;
1459 fse->max_height = format.height;
1461 return 0;
1465 * resizer_get_format - Handle get format by pads subdev method
1466 * @sd : pointer to v4l2 subdev structure
1467 * @fh : V4L2 subdev file handle
1468 * @fmt : pointer to v4l2 subdev format structure
1469 * return -EINVAL or zero on success
1471 static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1472 struct v4l2_subdev_format *fmt)
1474 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1475 struct v4l2_mbus_framefmt *format;
1477 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1478 if (format == NULL)
1479 return -EINVAL;
1481 fmt->format = *format;
1482 return 0;
1486 * resizer_set_format - Handle set format by pads subdev method
1487 * @sd : pointer to v4l2 subdev structure
1488 * @fh : V4L2 subdev file handle
1489 * @fmt : pointer to v4l2 subdev format structure
1490 * return -EINVAL or zero on success
1492 static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1493 struct v4l2_subdev_format *fmt)
1495 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1496 struct v4l2_mbus_framefmt *format;
1497 struct v4l2_rect *crop;
1499 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1500 if (format == NULL)
1501 return -EINVAL;
1503 resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1504 *format = fmt->format;
1506 if (fmt->pad == RESZ_PAD_SINK) {
1507 /* reset crop rectangle */
1508 crop = __resizer_get_crop(res, fh, fmt->which);
1509 crop->left = 0;
1510 crop->top = 0;
1511 crop->width = fmt->format.width;
1512 crop->height = fmt->format.height;
1514 /* Propagate the format from sink to source */
1515 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1516 fmt->which);
1517 *format = fmt->format;
1518 resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1519 fmt->which);
1522 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1523 /* Compute and store the active crop rectangle and resizer
1524 * ratios. format already points to the source pad active
1525 * format.
1527 res->crop.active = res->crop.request;
1528 resizer_calc_ratios(res, &res->crop.active, format,
1529 &res->ratio);
1532 return 0;
1535 static int resizer_link_validate(struct v4l2_subdev *sd,
1536 struct media_link *link,
1537 struct v4l2_subdev_format *source_fmt,
1538 struct v4l2_subdev_format *sink_fmt)
1540 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1541 struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
1543 omap3isp_resizer_max_rate(res, &pipe->max_rate);
1545 return v4l2_subdev_link_validate_default(sd, link,
1546 source_fmt, sink_fmt);
1550 * resizer_init_formats - Initialize formats on all pads
1551 * @sd: ISP resizer V4L2 subdevice
1552 * @fh: V4L2 subdev file handle
1554 * Initialize all pad formats with default values. If fh is not NULL, try
1555 * formats are initialized on the file handle. Otherwise active formats are
1556 * initialized on the device.
1558 static int resizer_init_formats(struct v4l2_subdev *sd,
1559 struct v4l2_subdev_fh *fh)
1561 struct v4l2_subdev_format format;
1563 memset(&format, 0, sizeof(format));
1564 format.pad = RESZ_PAD_SINK;
1565 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1566 format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1567 format.format.width = 4096;
1568 format.format.height = 4096;
1569 resizer_set_format(sd, fh, &format);
1571 return 0;
1574 /* subdev video operations */
1575 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1576 .s_stream = resizer_set_stream,
1579 /* subdev pad operations */
1580 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1581 .enum_mbus_code = resizer_enum_mbus_code,
1582 .enum_frame_size = resizer_enum_frame_size,
1583 .get_fmt = resizer_get_format,
1584 .set_fmt = resizer_set_format,
1585 .get_selection = resizer_get_selection,
1586 .set_selection = resizer_set_selection,
1587 .link_validate = resizer_link_validate,
1590 /* subdev operations */
1591 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1592 .video = &resizer_v4l2_video_ops,
1593 .pad = &resizer_v4l2_pad_ops,
1596 /* subdev internal operations */
1597 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1598 .open = resizer_init_formats,
1601 /* -----------------------------------------------------------------------------
1602 * Media entity operations
1606 * resizer_link_setup - Setup resizer connections.
1607 * @entity : Pointer to media entity structure
1608 * @local : Pointer to local pad array
1609 * @remote : Pointer to remote pad array
1610 * @flags : Link flags
1611 * return -EINVAL or zero on success
1613 static int resizer_link_setup(struct media_entity *entity,
1614 const struct media_pad *local,
1615 const struct media_pad *remote, u32 flags)
1617 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1618 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1620 switch (local->index | media_entity_type(remote->entity)) {
1621 case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1622 /* read from memory */
1623 if (flags & MEDIA_LNK_FL_ENABLED) {
1624 if (res->input == RESIZER_INPUT_VP)
1625 return -EBUSY;
1626 res->input = RESIZER_INPUT_MEMORY;
1627 } else {
1628 if (res->input == RESIZER_INPUT_MEMORY)
1629 res->input = RESIZER_INPUT_NONE;
1631 break;
1633 case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1634 /* read from ccdc or previewer */
1635 if (flags & MEDIA_LNK_FL_ENABLED) {
1636 if (res->input == RESIZER_INPUT_MEMORY)
1637 return -EBUSY;
1638 res->input = RESIZER_INPUT_VP;
1639 } else {
1640 if (res->input == RESIZER_INPUT_VP)
1641 res->input = RESIZER_INPUT_NONE;
1643 break;
1645 case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1646 /* resizer always write to memory */
1647 break;
1649 default:
1650 return -EINVAL;
1653 return 0;
1656 /* media operations */
1657 static const struct media_entity_operations resizer_media_ops = {
1658 .link_setup = resizer_link_setup,
1659 .link_validate = v4l2_subdev_link_validate,
1662 void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1664 v4l2_device_unregister_subdev(&res->subdev);
1665 omap3isp_video_unregister(&res->video_in);
1666 omap3isp_video_unregister(&res->video_out);
1669 int omap3isp_resizer_register_entities(struct isp_res_device *res,
1670 struct v4l2_device *vdev)
1672 int ret;
1674 /* Register the subdev and video nodes. */
1675 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1676 if (ret < 0)
1677 goto error;
1679 ret = omap3isp_video_register(&res->video_in, vdev);
1680 if (ret < 0)
1681 goto error;
1683 ret = omap3isp_video_register(&res->video_out, vdev);
1684 if (ret < 0)
1685 goto error;
1687 return 0;
1689 error:
1690 omap3isp_resizer_unregister_entities(res);
1691 return ret;
1694 /* -----------------------------------------------------------------------------
1695 * ISP resizer initialization and cleanup
1699 * resizer_init_entities - Initialize resizer subdev and media entity.
1700 * @res : Pointer to resizer device structure
1701 * return -ENOMEM or zero on success
1703 static int resizer_init_entities(struct isp_res_device *res)
1705 struct v4l2_subdev *sd = &res->subdev;
1706 struct media_pad *pads = res->pads;
1707 struct media_entity *me = &sd->entity;
1708 int ret;
1710 res->input = RESIZER_INPUT_NONE;
1712 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1713 sd->internal_ops = &resizer_v4l2_internal_ops;
1714 strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1715 sd->grp_id = 1 << 16; /* group ID for isp subdevs */
1716 v4l2_set_subdevdata(sd, res);
1717 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1719 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
1720 | MEDIA_PAD_FL_MUST_CONNECT;
1721 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1723 me->ops = &resizer_media_ops;
1724 ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1725 if (ret < 0)
1726 return ret;
1728 resizer_init_formats(sd, NULL);
1730 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1731 res->video_in.ops = &resizer_video_ops;
1732 res->video_in.isp = to_isp_device(res);
1733 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1734 res->video_in.bpl_alignment = 32;
1735 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1736 res->video_out.ops = &resizer_video_ops;
1737 res->video_out.isp = to_isp_device(res);
1738 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1739 res->video_out.bpl_alignment = 32;
1741 ret = omap3isp_video_init(&res->video_in, "resizer");
1742 if (ret < 0)
1743 goto error_video_in;
1745 ret = omap3isp_video_init(&res->video_out, "resizer");
1746 if (ret < 0)
1747 goto error_video_out;
1749 res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
1751 /* Connect the video nodes to the resizer subdev. */
1752 ret = media_entity_create_link(&res->video_in.video.entity, 0,
1753 &res->subdev.entity, RESZ_PAD_SINK, 0);
1754 if (ret < 0)
1755 goto error_link;
1757 ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1758 &res->video_out.video.entity, 0, 0);
1759 if (ret < 0)
1760 goto error_link;
1762 return 0;
1764 error_link:
1765 omap3isp_video_cleanup(&res->video_out);
1766 error_video_out:
1767 omap3isp_video_cleanup(&res->video_in);
1768 error_video_in:
1769 media_entity_cleanup(&res->subdev.entity);
1770 return ret;
1774 * isp_resizer_init - Resizer initialization.
1775 * @isp : Pointer to ISP device
1776 * return -ENOMEM or zero on success
1778 int omap3isp_resizer_init(struct isp_device *isp)
1780 struct isp_res_device *res = &isp->isp_res;
1782 init_waitqueue_head(&res->wait);
1783 atomic_set(&res->stopping, 0);
1784 return resizer_init_entities(res);
1787 void omap3isp_resizer_cleanup(struct isp_device *isp)
1789 struct isp_res_device *res = &isp->isp_res;
1791 omap3isp_video_cleanup(&res->video_in);
1792 omap3isp_video_cleanup(&res->video_out);
1793 media_entity_cleanup(&res->subdev.entity);