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 *
__resizer_get_format(struct isp_res_device * res,struct v4l2_subdev_fh * fh,unsigned int pad,enum v4l2_subdev_format_whence which)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 *
__resizer_get_crop(struct isp_res_device * res,struct v4l2_subdev_fh * fh,enum v4l2_subdev_format_whence which)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  */
resizer_set_filters(struct isp_res_device * res,const u16 * h_coeff,const u16 * v_coeff)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  */
resizer_set_bilinear(struct isp_res_device * res,enum resizer_chroma_algo type)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  * @order: order type.
210  */
resizer_set_ycpos(struct isp_res_device * res,enum v4l2_mbus_pixelcode pixelcode)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  */
resizer_set_phase(struct isp_res_device * res,u32 h_phase,u32 v_phase)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  */
resizer_set_luma(struct isp_res_device * res,struct resizer_luma_yenh * luma)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  */
resizer_set_source(struct isp_res_device * res,enum resizer_input_entity source)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  */
resizer_set_ratio(struct isp_res_device * res,const struct resizer_ratio * ratio)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  */
resizer_set_output_size(struct isp_res_device * res,u32 width,u32 height)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  */
resizer_set_output_offset(struct isp_res_device * res,u32 offset)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  */
resizer_set_start(struct isp_res_device * res,u32 left,u32 top)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  */
resizer_set_input_size(struct isp_res_device * res,u32 width,u32 height)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  */
resizer_set_input_offset(struct isp_res_device * res,u32 offset)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  */
resizer_set_intype(struct isp_res_device * res,enum resizer_colors_type type)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  */
__resizer_set_inaddr(struct isp_res_device * res,u32 addr)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  */
omap3isp_resizer_max_rate(struct isp_res_device * res,unsigned int * max_rate)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  */
resizer_adjust_bandwidth(struct isp_res_device * res)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  */
omap3isp_resizer_busy(struct isp_res_device * res)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  */
resizer_set_inaddr(struct isp_res_device * res,u32 addr)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  */
resizer_set_outaddr(struct isp_res_device * res,u32 addr)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 
resizer_print_status(struct isp_res_device * res)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 calculate resizer ratios
694  * @res: pointer to resizer private data structure
695  * @input: input frame size
696  * @output: output frame size
697  * @ratio : return calculated ratios
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 the 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 capabilitie 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  */
resizer_calc_ratios(struct isp_res_device * res,struct v4l2_rect * input,struct v4l2_mbus_framefmt * output,struct resizer_ratio * ratio)794 static void resizer_calc_ratios(struct isp_res_device *res,
795 				struct v4l2_rect *input,
796 				struct v4l2_mbus_framefmt *output,
797 				struct resizer_ratio *ratio)
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  * @crop_rect : current crop rectangle
922  * @ratio : resizer ratios
923  * return none
924  */
resizer_set_crop_params(struct isp_res_device * res,const struct v4l2_mbus_framefmt * input,const struct v4l2_mbus_framefmt * output)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 
resizer_configure(struct isp_res_device * res)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 
resizer_enable_oneshot(struct isp_res_device * res)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 
omap3isp_resizer_isr_frame_sync(struct isp_res_device * res)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 
resizer_isr_buffer(struct isp_res_device * res)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 
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->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))
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  */
omap3isp_resizer_isr(struct isp_res_device * res)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 
resizer_video_queue(struct isp_video * video,struct isp_buffer * buffer)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  */
resizer_set_stream(struct v4l2_subdev * sd,int enable)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_g_crop - handle get crop subdev operation
1192  * @sd : pointer to v4l2 subdev structure
1193  * @pad : subdev pad
1194  * @crop : pointer to crop structure
1195  * @which : active or try format
1196  * return zero
1197  */
resizer_g_crop(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh,struct v4l2_subdev_crop * crop)1198 static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1199 			  struct v4l2_subdev_crop *crop)
1200 {
1201 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1202 	struct v4l2_mbus_framefmt *format;
1203 	struct resizer_ratio ratio;
1204 
1205 	/* Only sink pad has crop capability */
1206 	if (crop->pad != RESZ_PAD_SINK)
1207 		return -EINVAL;
1208 
1209 	format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1210 	crop->rect = *__resizer_get_crop(res, fh, crop->which);
1211 	resizer_calc_ratios(res, &crop->rect, format, &ratio);
1212 
1213 	return 0;
1214 }
1215 
1216 /*
1217  * resizer_try_crop - mangles crop parameters.
1218  */
resizer_try_crop(const struct v4l2_mbus_framefmt * sink,const struct v4l2_mbus_framefmt * source,struct v4l2_rect * crop)1219 static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1220 			     const struct v4l2_mbus_framefmt *source,
1221 			     struct v4l2_rect *crop)
1222 {
1223 	const unsigned int spv = DEFAULT_PHASE;
1224 	const unsigned int sph = DEFAULT_PHASE;
1225 
1226 	/* Crop rectangle is constrained to the output size so that zoom ratio
1227 	 * cannot exceed +/-4.0.
1228 	 */
1229 	unsigned int min_width =
1230 		((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1231 	unsigned int min_height =
1232 		((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1233 	unsigned int max_width =
1234 		((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1235 	unsigned int max_height =
1236 		((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1237 
1238 	crop->width = clamp_t(u32, crop->width, min_width, max_width);
1239 	crop->height = clamp_t(u32, crop->height, min_height, max_height);
1240 
1241 	/* Crop can not go beyond of the input rectangle */
1242 	crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1243 	crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1244 			      sink->width - crop->left);
1245 	crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1246 	crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1247 			       sink->height - crop->top);
1248 }
1249 
1250 /*
1251  * resizer_s_crop - handle set crop subdev operation
1252  * @sd : pointer to v4l2 subdev structure
1253  * @pad : subdev pad
1254  * @crop : pointer to crop structure
1255  * @which : active or try format
1256  * return -EINVAL or zero when succeed
1257  */
resizer_s_crop(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh,struct v4l2_subdev_crop * crop)1258 static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1259 			  struct v4l2_subdev_crop *crop)
1260 {
1261 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1262 	struct isp_device *isp = to_isp_device(res);
1263 	struct v4l2_mbus_framefmt *format_sink, *format_source;
1264 	struct resizer_ratio ratio;
1265 
1266 	/* Only sink pad has crop capability */
1267 	if (crop->pad != RESZ_PAD_SINK)
1268 		return -EINVAL;
1269 
1270 	format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1271 					   crop->which);
1272 	format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1273 					     crop->which);
1274 
1275 	dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1276 		crop->rect.left, crop->rect.top, crop->rect.width,
1277 		crop->rect.height, crop->which);
1278 
1279 	dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1280 		format_sink->width, format_sink->height,
1281 		format_source->width, format_source->height);
1282 
1283 	resizer_try_crop(format_sink, format_source, &crop->rect);
1284 	*__resizer_get_crop(res, fh, crop->which) = crop->rect;
1285 	resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1286 
1287 	if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1288 		return 0;
1289 
1290 	res->ratio = ratio;
1291 	res->crop.active = crop->rect;
1292 
1293 	/*
1294 	 * s_crop can be called while streaming is on. In this case
1295 	 * the crop values will be set in the next IRQ.
1296 	 */
1297 	if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1298 		res->applycrop = 1;
1299 
1300 	return 0;
1301 }
1302 
1303 /* resizer pixel formats */
1304 static const unsigned int resizer_formats[] = {
1305 	V4L2_MBUS_FMT_UYVY8_1X16,
1306 	V4L2_MBUS_FMT_YUYV8_1X16,
1307 };
1308 
resizer_max_in_width(struct isp_res_device * res)1309 static unsigned int resizer_max_in_width(struct isp_res_device *res)
1310 {
1311 	struct isp_device *isp = to_isp_device(res);
1312 
1313 	if (res->input == RESIZER_INPUT_MEMORY) {
1314 		return MAX_IN_WIDTH_MEMORY_MODE;
1315 	} else {
1316 		if (isp->revision == ISP_REVISION_1_0)
1317 			return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1318 		else
1319 			return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1320 	}
1321 }
1322 
1323 /*
1324  * resizer_try_format - Handle try format by pad subdev method
1325  * @res   : ISP resizer device
1326  * @fh    : V4L2 subdev file handle
1327  * @pad   : pad num
1328  * @fmt   : pointer to v4l2 format structure
1329  * @which : wanted subdev format
1330  */
resizer_try_format(struct isp_res_device * res,struct v4l2_subdev_fh * fh,unsigned int pad,struct v4l2_mbus_framefmt * fmt,enum v4l2_subdev_format_whence which)1331 static void resizer_try_format(struct isp_res_device *res,
1332 			       struct v4l2_subdev_fh *fh, unsigned int pad,
1333 			       struct v4l2_mbus_framefmt *fmt,
1334 			       enum v4l2_subdev_format_whence which)
1335 {
1336 	struct v4l2_mbus_framefmt *format;
1337 	struct resizer_ratio ratio;
1338 	struct v4l2_rect crop;
1339 
1340 	switch (pad) {
1341 	case RESZ_PAD_SINK:
1342 		if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1343 		    fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1344 			fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1345 
1346 		fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1347 				     resizer_max_in_width(res));
1348 		fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1349 				      MAX_IN_HEIGHT);
1350 		break;
1351 
1352 	case RESZ_PAD_SOURCE:
1353 		format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1354 		fmt->code = format->code;
1355 
1356 		crop = *__resizer_get_crop(res, fh, which);
1357 		resizer_calc_ratios(res, &crop, fmt, &ratio);
1358 		break;
1359 	}
1360 
1361 	fmt->colorspace = V4L2_COLORSPACE_JPEG;
1362 	fmt->field = V4L2_FIELD_NONE;
1363 }
1364 
1365 /*
1366  * resizer_enum_mbus_code - Handle pixel format enumeration
1367  * @sd     : pointer to v4l2 subdev structure
1368  * @fh     : V4L2 subdev file handle
1369  * @code   : pointer to v4l2_subdev_mbus_code_enum structure
1370  * return -EINVAL or zero on success
1371  */
resizer_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh,struct v4l2_subdev_mbus_code_enum * code)1372 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1373 				  struct v4l2_subdev_fh *fh,
1374 				  struct v4l2_subdev_mbus_code_enum *code)
1375 {
1376 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1377 	struct v4l2_mbus_framefmt *format;
1378 
1379 	if (code->pad == RESZ_PAD_SINK) {
1380 		if (code->index >= ARRAY_SIZE(resizer_formats))
1381 			return -EINVAL;
1382 
1383 		code->code = resizer_formats[code->index];
1384 	} else {
1385 		if (code->index != 0)
1386 			return -EINVAL;
1387 
1388 		format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1389 					      V4L2_SUBDEV_FORMAT_TRY);
1390 		code->code = format->code;
1391 	}
1392 
1393 	return 0;
1394 }
1395 
resizer_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh,struct v4l2_subdev_frame_size_enum * fse)1396 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1397 				   struct v4l2_subdev_fh *fh,
1398 				   struct v4l2_subdev_frame_size_enum *fse)
1399 {
1400 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1401 	struct v4l2_mbus_framefmt format;
1402 
1403 	if (fse->index != 0)
1404 		return -EINVAL;
1405 
1406 	format.code = fse->code;
1407 	format.width = 1;
1408 	format.height = 1;
1409 	resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1410 	fse->min_width = format.width;
1411 	fse->min_height = format.height;
1412 
1413 	if (format.code != fse->code)
1414 		return -EINVAL;
1415 
1416 	format.code = fse->code;
1417 	format.width = -1;
1418 	format.height = -1;
1419 	resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1420 	fse->max_width = format.width;
1421 	fse->max_height = format.height;
1422 
1423 	return 0;
1424 }
1425 
1426 /*
1427  * resizer_get_format - Handle get format by pads subdev method
1428  * @sd    : pointer to v4l2 subdev structure
1429  * @fh    : V4L2 subdev file handle
1430  * @fmt   : pointer to v4l2 subdev format structure
1431  * return -EINVAL or zero on success
1432  */
resizer_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh,struct v4l2_subdev_format * fmt)1433 static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1434 			      struct v4l2_subdev_format *fmt)
1435 {
1436 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1437 	struct v4l2_mbus_framefmt *format;
1438 
1439 	format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1440 	if (format == NULL)
1441 		return -EINVAL;
1442 
1443 	fmt->format = *format;
1444 	return 0;
1445 }
1446 
1447 /*
1448  * resizer_set_format - Handle set format by pads subdev method
1449  * @sd    : pointer to v4l2 subdev structure
1450  * @fh    : V4L2 subdev file handle
1451  * @fmt   : pointer to v4l2 subdev format structure
1452  * return -EINVAL or zero on success
1453  */
resizer_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh,struct v4l2_subdev_format * fmt)1454 static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1455 			      struct v4l2_subdev_format *fmt)
1456 {
1457 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1458 	struct v4l2_mbus_framefmt *format;
1459 	struct v4l2_rect *crop;
1460 
1461 	format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1462 	if (format == NULL)
1463 		return -EINVAL;
1464 
1465 	resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1466 	*format = fmt->format;
1467 
1468 	if (fmt->pad == RESZ_PAD_SINK) {
1469 		/* reset crop rectangle */
1470 		crop = __resizer_get_crop(res, fh, fmt->which);
1471 		crop->left = 0;
1472 		crop->top = 0;
1473 		crop->width = fmt->format.width;
1474 		crop->height = fmt->format.height;
1475 
1476 		/* Propagate the format from sink to source */
1477 		format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1478 					      fmt->which);
1479 		*format = fmt->format;
1480 		resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1481 				   fmt->which);
1482 	}
1483 
1484 	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1485 		/* Compute and store the active crop rectangle and resizer
1486 		 * ratios. format already points to the source pad active
1487 		 * format.
1488 		 */
1489 		res->crop.active = res->crop.request;
1490 		resizer_calc_ratios(res, &res->crop.active, format,
1491 				       &res->ratio);
1492 	}
1493 
1494 	return 0;
1495 }
1496 
1497 /*
1498  * resizer_init_formats - Initialize formats on all pads
1499  * @sd: ISP resizer V4L2 subdevice
1500  * @fh: V4L2 subdev file handle
1501  *
1502  * Initialize all pad formats with default values. If fh is not NULL, try
1503  * formats are initialized on the file handle. Otherwise active formats are
1504  * initialized on the device.
1505  */
resizer_init_formats(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)1506 static int resizer_init_formats(struct v4l2_subdev *sd,
1507 				struct v4l2_subdev_fh *fh)
1508 {
1509 	struct v4l2_subdev_format format;
1510 
1511 	memset(&format, 0, sizeof(format));
1512 	format.pad = RESZ_PAD_SINK;
1513 	format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1514 	format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1515 	format.format.width = 4096;
1516 	format.format.height = 4096;
1517 	resizer_set_format(sd, fh, &format);
1518 
1519 	return 0;
1520 }
1521 
1522 /* subdev video operations */
1523 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1524 	.s_stream = resizer_set_stream,
1525 };
1526 
1527 /* subdev pad operations */
1528 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1529 	.enum_mbus_code = resizer_enum_mbus_code,
1530 	.enum_frame_size = resizer_enum_frame_size,
1531 	.get_fmt = resizer_get_format,
1532 	.set_fmt = resizer_set_format,
1533 	.get_crop = resizer_g_crop,
1534 	.set_crop = resizer_s_crop,
1535 };
1536 
1537 /* subdev operations */
1538 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1539 	.video = &resizer_v4l2_video_ops,
1540 	.pad = &resizer_v4l2_pad_ops,
1541 };
1542 
1543 /* subdev internal operations */
1544 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1545 	.open = resizer_init_formats,
1546 };
1547 
1548 /* -----------------------------------------------------------------------------
1549  * Media entity operations
1550  */
1551 
1552 /*
1553  * resizer_link_setup - Setup resizer connections.
1554  * @entity : Pointer to media entity structure
1555  * @local  : Pointer to local pad array
1556  * @remote : Pointer to remote pad array
1557  * @flags  : Link flags
1558  * return -EINVAL or zero on success
1559  */
resizer_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)1560 static int resizer_link_setup(struct media_entity *entity,
1561 			      const struct media_pad *local,
1562 			      const struct media_pad *remote, u32 flags)
1563 {
1564 	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1565 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
1566 
1567 	switch (local->index | media_entity_type(remote->entity)) {
1568 	case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1569 		/* read from memory */
1570 		if (flags & MEDIA_LNK_FL_ENABLED) {
1571 			if (res->input == RESIZER_INPUT_VP)
1572 				return -EBUSY;
1573 			res->input = RESIZER_INPUT_MEMORY;
1574 		} else {
1575 			if (res->input == RESIZER_INPUT_MEMORY)
1576 				res->input = RESIZER_INPUT_NONE;
1577 		}
1578 		break;
1579 
1580 	case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1581 		/* read from ccdc or previewer */
1582 		if (flags & MEDIA_LNK_FL_ENABLED) {
1583 			if (res->input == RESIZER_INPUT_MEMORY)
1584 				return -EBUSY;
1585 			res->input = RESIZER_INPUT_VP;
1586 		} else {
1587 			if (res->input == RESIZER_INPUT_VP)
1588 				res->input = RESIZER_INPUT_NONE;
1589 		}
1590 		break;
1591 
1592 	case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1593 		/* resizer always write to memory */
1594 		break;
1595 
1596 	default:
1597 		return -EINVAL;
1598 	}
1599 
1600 	return 0;
1601 }
1602 
1603 /* media operations */
1604 static const struct media_entity_operations resizer_media_ops = {
1605 	.link_setup = resizer_link_setup,
1606 };
1607 
omap3isp_resizer_unregister_entities(struct isp_res_device * res)1608 void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1609 {
1610 	v4l2_device_unregister_subdev(&res->subdev);
1611 	omap3isp_video_unregister(&res->video_in);
1612 	omap3isp_video_unregister(&res->video_out);
1613 }
1614 
omap3isp_resizer_register_entities(struct isp_res_device * res,struct v4l2_device * vdev)1615 int omap3isp_resizer_register_entities(struct isp_res_device *res,
1616 				       struct v4l2_device *vdev)
1617 {
1618 	int ret;
1619 
1620 	/* Register the subdev and video nodes. */
1621 	ret = v4l2_device_register_subdev(vdev, &res->subdev);
1622 	if (ret < 0)
1623 		goto error;
1624 
1625 	ret = omap3isp_video_register(&res->video_in, vdev);
1626 	if (ret < 0)
1627 		goto error;
1628 
1629 	ret = omap3isp_video_register(&res->video_out, vdev);
1630 	if (ret < 0)
1631 		goto error;
1632 
1633 	return 0;
1634 
1635 error:
1636 	omap3isp_resizer_unregister_entities(res);
1637 	return ret;
1638 }
1639 
1640 /* -----------------------------------------------------------------------------
1641  * ISP resizer initialization and cleanup
1642  */
1643 
1644 /*
1645  * resizer_init_entities - Initialize resizer subdev and media entity.
1646  * @res : Pointer to resizer device structure
1647  * return -ENOMEM or zero on success
1648  */
resizer_init_entities(struct isp_res_device * res)1649 static int resizer_init_entities(struct isp_res_device *res)
1650 {
1651 	struct v4l2_subdev *sd = &res->subdev;
1652 	struct media_pad *pads = res->pads;
1653 	struct media_entity *me = &sd->entity;
1654 	int ret;
1655 
1656 	res->input = RESIZER_INPUT_NONE;
1657 
1658 	v4l2_subdev_init(sd, &resizer_v4l2_ops);
1659 	sd->internal_ops = &resizer_v4l2_internal_ops;
1660 	strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1661 	sd->grp_id = 1 << 16;	/* group ID for isp subdevs */
1662 	v4l2_set_subdevdata(sd, res);
1663 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1664 
1665 	pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1666 	pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1667 
1668 	me->ops = &resizer_media_ops;
1669 	ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1670 	if (ret < 0)
1671 		return ret;
1672 
1673 	resizer_init_formats(sd, NULL);
1674 
1675 	res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1676 	res->video_in.ops = &resizer_video_ops;
1677 	res->video_in.isp = to_isp_device(res);
1678 	res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1679 	res->video_in.bpl_alignment = 32;
1680 	res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1681 	res->video_out.ops = &resizer_video_ops;
1682 	res->video_out.isp = to_isp_device(res);
1683 	res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1684 	res->video_out.bpl_alignment = 32;
1685 
1686 	ret = omap3isp_video_init(&res->video_in, "resizer");
1687 	if (ret < 0)
1688 		goto error_video_in;
1689 
1690 	ret = omap3isp_video_init(&res->video_out, "resizer");
1691 	if (ret < 0)
1692 		goto error_video_out;
1693 
1694 	/* Connect the video nodes to the resizer subdev. */
1695 	ret = media_entity_create_link(&res->video_in.video.entity, 0,
1696 			&res->subdev.entity, RESZ_PAD_SINK, 0);
1697 	if (ret < 0)
1698 		goto error_link;
1699 
1700 	ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1701 			&res->video_out.video.entity, 0, 0);
1702 	if (ret < 0)
1703 		goto error_link;
1704 
1705 	return 0;
1706 
1707 error_link:
1708 	omap3isp_video_cleanup(&res->video_out);
1709 error_video_out:
1710 	omap3isp_video_cleanup(&res->video_in);
1711 error_video_in:
1712 	media_entity_cleanup(&res->subdev.entity);
1713 	return ret;
1714 }
1715 
1716 /*
1717  * isp_resizer_init - Resizer initialization.
1718  * @isp : Pointer to ISP device
1719  * return -ENOMEM or zero on success
1720  */
omap3isp_resizer_init(struct isp_device * isp)1721 int omap3isp_resizer_init(struct isp_device *isp)
1722 {
1723 	struct isp_res_device *res = &isp->isp_res;
1724 
1725 	init_waitqueue_head(&res->wait);
1726 	atomic_set(&res->stopping, 0);
1727 	return resizer_init_entities(res);
1728 }
1729 
omap3isp_resizer_cleanup(struct isp_device * isp)1730 void omap3isp_resizer_cleanup(struct isp_device *isp)
1731 {
1732 	struct isp_res_device *res = &isp->isp_res;
1733 
1734 	omap3isp_video_cleanup(&res->video_in);
1735 	omap3isp_video_cleanup(&res->video_out);
1736 	media_entity_cleanup(&res->subdev.entity);
1737 }
1738