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