Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ispresizer.c
Go to the documentation of this file.
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 <[email protected]>
10  * Sakari Ailus <[email protected]>
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,
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,
201  else
202  isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
204 }
205 
206 /*
207  * resizer_set_ycpos - Luminance and chrominance order
208  * @res: Device context.
209  * @order: order type.
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) {
218  isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
220  break;
222  isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
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) &
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)
282  rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
284  rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
286  rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
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,
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,
308  else
309  isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
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) &
329  rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
331  rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
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)
373  rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
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)
416  rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
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)
438  rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
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,
473  else
474  isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
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  */
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,
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,
617 }
618 
619 /*
620  * omap3isp_resizer_busy - Checks if ISP resizer is busy.
621  *
622  * Returns busy field from ISPRSZ_PCR register.
623  */
625 {
626  struct isp_device *isp = to_isp_device(res);
627 
628  return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
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,
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,
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,
900 
901  if (ratio->horz <= MID_RESIZE_VALUE) {
902  upscaled_width = (output->width - 1) * ratio->horz
903  + 32 * sph + 16;
904  width = (upscaled_width >> 8) + 7;
905  } else {
906  upscaled_width = (output->width - 1) * ratio->horz
907  + 64 * sph + 32;
908  width = (upscaled_width >> 8) + 7;
909  }
910 
911  /* Center the new crop rectangle. */
912  input->left += (input->width - width) / 2;
913  input->top += (input->height - height) / 2;
914  input->width = width;
915  input->height = height;
916 }
917 
918 /*
919  * resizer_set_crop_params - Setup hardware with cropping parameters
920  * @res : resizer private structure
921  * @crop_rect : current crop rectangle
922  * @ratio : resizer ratios
923  * return none
924  */
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,
1012 }
1013 
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->isp_addr);
1044  restart = 1;
1045  }
1046 
1048 
1049  if (res->input == RESIZER_INPUT_MEMORY) {
1050  buffer = omap3isp_video_buffer_next(&res->video_in);
1051  if (buffer != NULL)
1052  resizer_set_inaddr(res, buffer->isp_addr);
1053  pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1054  }
1055 
1056  if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
1057  if (isp_pipeline_ready(pipe))
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  */
1076 {
1077  struct v4l2_mbus_framefmt *informat, *outformat;
1078 
1080  return;
1081 
1082  if (res->applycrop) {
1083  outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1085  informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
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->isp_addr);
1105 
1106  /*
1107  * We now have a buffer queued on the output. Despite what the
1108  * TRM says, the resizer can't be restarted immediately.
1109  * Enabling it in one shot mode in the middle of a frame (or at
1110  * least asynchronously to the frame) results in the output
1111  * being shifted randomly left/right and up/down, as if the
1112  * hardware didn't synchronize itself to the beginning of the
1113  * frame correctly.
1114  *
1115  * Restart the resizer on the next sync interrupt if running in
1116  * continuous mode or when starting the stream.
1117  */
1118  if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1119  resizer_set_outaddr(res, buffer->isp_addr);
1120 
1121  return 0;
1122 }
1123 
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 
1154  resizer_configure(res);
1155  resizer_print_status(res);
1156  }
1157 
1158  switch (enable) {
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 
1168  if (res->input == RESIZER_INPUT_MEMORY)
1171 
1172  resizer_enable_oneshot(res);
1173  break;
1174 
1176  if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1177  &res->stopping))
1178  dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
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) {
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[] = {
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)
1356  else
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,
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 /*
1536  * resizer_init_formats - Initialize formats on all pads
1537  * @sd: ISP resizer V4L2 subdevice
1538  * @fh: V4L2 subdev file handle
1539  *
1540  * Initialize all pad formats with default values. If fh is not NULL, try
1541  * formats are initialized on the file handle. Otherwise active formats are
1542  * initialized on the device.
1543  */
1544 static int resizer_init_formats(struct v4l2_subdev *sd,
1545  struct v4l2_subdev_fh *fh)
1546 {
1547  struct v4l2_subdev_format format;
1548 
1549  memset(&format, 0, sizeof(format));
1550  format.pad = RESZ_PAD_SINK;
1551  format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1552  format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1553  format.format.width = 4096;
1554  format.format.height = 4096;
1555  resizer_set_format(sd, fh, &format);
1556 
1557  return 0;
1558 }
1559 
1560 /* subdev video operations */
1561 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1562  .s_stream = resizer_set_stream,
1563 };
1564 
1565 /* subdev pad operations */
1566 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1567  .enum_mbus_code = resizer_enum_mbus_code,
1568  .enum_frame_size = resizer_enum_frame_size,
1569  .get_fmt = resizer_get_format,
1570  .set_fmt = resizer_set_format,
1571  .get_selection = resizer_get_selection,
1572  .set_selection = resizer_set_selection,
1573 };
1574 
1575 /* subdev operations */
1576 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1577  .video = &resizer_v4l2_video_ops,
1578  .pad = &resizer_v4l2_pad_ops,
1579 };
1580 
1581 /* subdev internal operations */
1582 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1583  .open = resizer_init_formats,
1584 };
1585 
1586 /* -----------------------------------------------------------------------------
1587  * Media entity operations
1588  */
1589 
1590 /*
1591  * resizer_link_setup - Setup resizer connections.
1592  * @entity : Pointer to media entity structure
1593  * @local : Pointer to local pad array
1594  * @remote : Pointer to remote pad array
1595  * @flags : Link flags
1596  * return -EINVAL or zero on success
1597  */
1598 static int resizer_link_setup(struct media_entity *entity,
1599  const struct media_pad *local,
1600  const struct media_pad *remote, u32 flags)
1601 {
1602  struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1603  struct isp_res_device *res = v4l2_get_subdevdata(sd);
1604 
1605  switch (local->index | media_entity_type(remote->entity)) {
1607  /* read from memory */
1608  if (flags & MEDIA_LNK_FL_ENABLED) {
1609  if (res->input == RESIZER_INPUT_VP)
1610  return -EBUSY;
1611  res->input = RESIZER_INPUT_MEMORY;
1612  } else {
1613  if (res->input == RESIZER_INPUT_MEMORY)
1614  res->input = RESIZER_INPUT_NONE;
1615  }
1616  break;
1617 
1619  /* read from ccdc or previewer */
1620  if (flags & MEDIA_LNK_FL_ENABLED) {
1621  if (res->input == RESIZER_INPUT_MEMORY)
1622  return -EBUSY;
1623  res->input = RESIZER_INPUT_VP;
1624  } else {
1625  if (res->input == RESIZER_INPUT_VP)
1626  res->input = RESIZER_INPUT_NONE;
1627  }
1628  break;
1629 
1631  /* resizer always write to memory */
1632  break;
1633 
1634  default:
1635  return -EINVAL;
1636  }
1637 
1638  return 0;
1639 }
1640 
1641 /* media operations */
1642 static const struct media_entity_operations resizer_media_ops = {
1643  .link_setup = resizer_link_setup,
1644  .link_validate = v4l2_subdev_link_validate,
1645 };
1646 
1648 {
1652 }
1653 
1655  struct v4l2_device *vdev)
1656 {
1657  int ret;
1658 
1659  /* Register the subdev and video nodes. */
1660  ret = v4l2_device_register_subdev(vdev, &res->subdev);
1661  if (ret < 0)
1662  goto error;
1663 
1664  ret = omap3isp_video_register(&res->video_in, vdev);
1665  if (ret < 0)
1666  goto error;
1667 
1668  ret = omap3isp_video_register(&res->video_out, vdev);
1669  if (ret < 0)
1670  goto error;
1671 
1672  return 0;
1673 
1674 error:
1676  return ret;
1677 }
1678 
1679 /* -----------------------------------------------------------------------------
1680  * ISP resizer initialization and cleanup
1681  */
1682 
1683 /*
1684  * resizer_init_entities - Initialize resizer subdev and media entity.
1685  * @res : Pointer to resizer device structure
1686  * return -ENOMEM or zero on success
1687  */
1688 static int resizer_init_entities(struct isp_res_device *res)
1689 {
1690  struct v4l2_subdev *sd = &res->subdev;
1691  struct media_pad *pads = res->pads;
1692  struct media_entity *me = &sd->entity;
1693  int ret;
1694 
1695  res->input = RESIZER_INPUT_NONE;
1696 
1697  v4l2_subdev_init(sd, &resizer_v4l2_ops);
1698  sd->internal_ops = &resizer_v4l2_internal_ops;
1699  strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1700  sd->grp_id = 1 << 16; /* group ID for isp subdevs */
1701  v4l2_set_subdevdata(sd, res);
1703 
1706 
1707  me->ops = &resizer_media_ops;
1708  ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1709  if (ret < 0)
1710  return ret;
1711 
1712  resizer_init_formats(sd, NULL);
1713 
1715  res->video_in.ops = &resizer_video_ops;
1716  res->video_in.isp = to_isp_device(res);
1717  res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1718  res->video_in.bpl_alignment = 32;
1720  res->video_out.ops = &resizer_video_ops;
1721  res->video_out.isp = to_isp_device(res);
1722  res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1723  res->video_out.bpl_alignment = 32;
1724 
1725  ret = omap3isp_video_init(&res->video_in, "resizer");
1726  if (ret < 0)
1727  goto error_video_in;
1728 
1729  ret = omap3isp_video_init(&res->video_out, "resizer");
1730  if (ret < 0)
1731  goto error_video_out;
1732 
1733  res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
1734 
1735  /* Connect the video nodes to the resizer subdev. */
1736  ret = media_entity_create_link(&res->video_in.video.entity, 0,
1737  &res->subdev.entity, RESZ_PAD_SINK, 0);
1738  if (ret < 0)
1739  goto error_link;
1740 
1741  ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1742  &res->video_out.video.entity, 0, 0);
1743  if (ret < 0)
1744  goto error_link;
1745 
1746  return 0;
1747 
1748 error_link:
1750 error_video_out:
1752 error_video_in:
1753  media_entity_cleanup(&res->subdev.entity);
1754  return ret;
1755 }
1756 
1757 /*
1758  * isp_resizer_init - Resizer initialization.
1759  * @isp : Pointer to ISP device
1760  * return -ENOMEM or zero on success
1761  */
1763 {
1764  struct isp_res_device *res = &isp->isp_res;
1765 
1766  init_waitqueue_head(&res->wait);
1767  atomic_set(&res->stopping, 0);
1768  return resizer_init_entities(res);
1769 }
1770 
1772 {
1773  struct isp_res_device *res = &isp->isp_res;
1774 
1777  media_entity_cleanup(&res->subdev.entity);
1778 }