4 * Copyright (C) 2005-2010 Texas Instruments.
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
10 * Based on the OMAP2 camera driver
11 * Video-for-Linux (Version 2) camera capture driver for
12 * the OMAP24xx camera controller.
14 * Author: Andy Lowe (source@mvista.com)
16 * Copyright (C) 2004 MontaVista Software, Inc.
17 * Copyright (C) 2010 Texas Instruments.
21 #include <linux/module.h>
22 #include <linux/errno.h>
23 #include <linux/kernel.h>
24 #include <linux/types.h>
25 #include <linux/videodev2.h>
27 #include <linux/dma-mapping.h>
29 #include <video/omapfb_dss.h>
31 #include "omap_voutlib.h"
33 MODULE_AUTHOR("Texas Instruments");
34 MODULE_DESCRIPTION("OMAP Video library");
35 MODULE_LICENSE("GPL");
37 /* Return the default overlay cropping rectangle in crop given the image
38 * size in pix and the video display size in fbuf. The default
39 * cropping rectangle is the largest rectangle no larger than the capture size
40 * that will fit on the display. The default cropping rectangle is centered in
41 * the image. All dimensions and offsets are rounded down to even numbers.
43 void omap_vout_default_crop(struct v4l2_pix_format
*pix
,
44 struct v4l2_framebuffer
*fbuf
, struct v4l2_rect
*crop
)
46 crop
->width
= (pix
->width
< fbuf
->fmt
.width
) ?
47 pix
->width
: fbuf
->fmt
.width
;
48 crop
->height
= (pix
->height
< fbuf
->fmt
.height
) ?
49 pix
->height
: fbuf
->fmt
.height
;
52 crop
->left
= ((pix
->width
- crop
->width
) >> 1) & ~1;
53 crop
->top
= ((pix
->height
- crop
->height
) >> 1) & ~1;
55 EXPORT_SYMBOL_GPL(omap_vout_default_crop
);
57 /* Given a new render window in new_win, adjust the window to the
58 * nearest supported configuration. The adjusted window parameters are
59 * returned in new_win.
60 * Returns zero if successful, or -EINVAL if the requested window is
61 * impossible and cannot reasonably be adjusted.
63 int omap_vout_try_window(struct v4l2_framebuffer
*fbuf
,
64 struct v4l2_window
*new_win
)
66 struct v4l2_rect try_win
;
68 /* make a working copy of the new_win rectangle */
71 /* adjust the preview window so it fits on the display by clipping any
74 if (try_win
.left
< 0) {
75 try_win
.width
+= try_win
.left
;
78 if (try_win
.top
< 0) {
79 try_win
.height
+= try_win
.top
;
82 try_win
.width
= (try_win
.width
< fbuf
->fmt
.width
) ?
83 try_win
.width
: fbuf
->fmt
.width
;
84 try_win
.height
= (try_win
.height
< fbuf
->fmt
.height
) ?
85 try_win
.height
: fbuf
->fmt
.height
;
86 if (try_win
.left
+ try_win
.width
> fbuf
->fmt
.width
)
87 try_win
.width
= fbuf
->fmt
.width
- try_win
.left
;
88 if (try_win
.top
+ try_win
.height
> fbuf
->fmt
.height
)
89 try_win
.height
= fbuf
->fmt
.height
- try_win
.top
;
93 if (try_win
.width
<= 0 || try_win
.height
<= 0)
96 /* We now have a valid preview window, so go with it */
98 new_win
->field
= V4L2_FIELD_NONE
;
99 new_win
->clips
= NULL
;
100 new_win
->clipcount
= 0;
101 new_win
->bitmap
= NULL
;
105 EXPORT_SYMBOL_GPL(omap_vout_try_window
);
107 /* Given a new render window in new_win, adjust the window to the
108 * nearest supported configuration. The image cropping window in crop
109 * will also be adjusted if necessary. Preference is given to keeping the
110 * the window as close to the requested configuration as possible. If
111 * successful, new_win, vout->win, and crop are updated.
112 * Returns zero if successful, or -EINVAL if the requested preview window is
113 * impossible and cannot reasonably be adjusted.
115 int omap_vout_new_window(struct v4l2_rect
*crop
,
116 struct v4l2_window
*win
, struct v4l2_framebuffer
*fbuf
,
117 struct v4l2_window
*new_win
)
121 err
= omap_vout_try_window(fbuf
, new_win
);
125 /* update our preview window */
127 win
->field
= new_win
->field
;
128 win
->chromakey
= new_win
->chromakey
;
130 /* Adjust the cropping window to allow for resizing limitation */
131 if (omap_vout_dss_omap24xx()) {
132 /* For 24xx limit is 8x to 1/2x scaling. */
133 if ((crop
->height
/win
->w
.height
) >= 2)
134 crop
->height
= win
->w
.height
* 2;
136 if ((crop
->width
/win
->w
.width
) >= 2)
137 crop
->width
= win
->w
.width
* 2;
139 if (crop
->width
> 768) {
140 /* The OMAP2420 vertical resizing line buffer is 768
141 * pixels wide. If the cropped image is wider than
142 * 768 pixels then it cannot be vertically resized.
144 if (crop
->height
!= win
->w
.height
)
147 } else if (omap_vout_dss_omap34xx()) {
148 /* For 34xx limit is 8x to 1/4x scaling. */
149 if ((crop
->height
/win
->w
.height
) >= 4)
150 crop
->height
= win
->w
.height
* 4;
152 if ((crop
->width
/win
->w
.width
) >= 4)
153 crop
->width
= win
->w
.width
* 4;
157 EXPORT_SYMBOL_GPL(omap_vout_new_window
);
159 /* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
160 * the nearest supported configuration. The image render window in win will
161 * also be adjusted if necessary. The preview window is adjusted such that the
162 * horizontal and vertical rescaling ratios stay constant. If the render
163 * window would fall outside the display boundaries, the cropping rectangle
164 * will also be adjusted to maintain the rescaling ratios. If successful, crop
165 * and win are updated.
166 * Returns zero if successful, or -EINVAL if the requested cropping rectangle is
167 * impossible and cannot reasonably be adjusted.
169 int omap_vout_new_crop(struct v4l2_pix_format
*pix
,
170 struct v4l2_rect
*crop
, struct v4l2_window
*win
,
171 struct v4l2_framebuffer
*fbuf
, const struct v4l2_rect
*new_crop
)
173 struct v4l2_rect try_crop
;
174 unsigned long vresize
, hresize
;
176 /* make a working copy of the new_crop rectangle */
177 try_crop
= *new_crop
;
179 /* adjust the cropping rectangle so it fits in the image */
180 if (try_crop
.left
< 0) {
181 try_crop
.width
+= try_crop
.left
;
184 if (try_crop
.top
< 0) {
185 try_crop
.height
+= try_crop
.top
;
188 try_crop
.width
= (try_crop
.width
< pix
->width
) ?
189 try_crop
.width
: pix
->width
;
190 try_crop
.height
= (try_crop
.height
< pix
->height
) ?
191 try_crop
.height
: pix
->height
;
192 if (try_crop
.left
+ try_crop
.width
> pix
->width
)
193 try_crop
.width
= pix
->width
- try_crop
.left
;
194 if (try_crop
.top
+ try_crop
.height
> pix
->height
)
195 try_crop
.height
= pix
->height
- try_crop
.top
;
197 try_crop
.width
&= ~1;
198 try_crop
.height
&= ~1;
200 if (try_crop
.width
<= 0 || try_crop
.height
<= 0)
203 if (omap_vout_dss_omap24xx()) {
204 if (try_crop
.height
!= win
->w
.height
) {
205 /* If we're resizing vertically, we can't support a
206 * crop width wider than 768 pixels.
208 if (try_crop
.width
> 768)
209 try_crop
.width
= 768;
212 /* vertical resizing */
213 vresize
= (1024 * try_crop
.height
) / win
->w
.height
;
214 if (omap_vout_dss_omap24xx() && (vresize
> 2048))
216 else if (omap_vout_dss_omap34xx() && (vresize
> 4096))
219 win
->w
.height
= ((1024 * try_crop
.height
) / vresize
) & ~1;
220 if (win
->w
.height
== 0)
222 if (win
->w
.height
+ win
->w
.top
> fbuf
->fmt
.height
) {
223 /* We made the preview window extend below the bottom of the
224 * display, so clip it to the display boundary and resize the
225 * cropping height to maintain the vertical resizing ratio.
227 win
->w
.height
= (fbuf
->fmt
.height
- win
->w
.top
) & ~1;
228 if (try_crop
.height
== 0)
231 /* horizontal resizing */
232 hresize
= (1024 * try_crop
.width
) / win
->w
.width
;
233 if (omap_vout_dss_omap24xx() && (hresize
> 2048))
235 else if (omap_vout_dss_omap34xx() && (hresize
> 4096))
238 win
->w
.width
= ((1024 * try_crop
.width
) / hresize
) & ~1;
239 if (win
->w
.width
== 0)
241 if (win
->w
.width
+ win
->w
.left
> fbuf
->fmt
.width
) {
242 /* We made the preview window extend past the right side of the
243 * display, so clip it to the display boundary and resize the
244 * cropping width to maintain the horizontal resizing ratio.
246 win
->w
.width
= (fbuf
->fmt
.width
- win
->w
.left
) & ~1;
247 if (try_crop
.width
== 0)
250 if (omap_vout_dss_omap24xx()) {
251 if ((try_crop
.height
/win
->w
.height
) >= 2)
252 try_crop
.height
= win
->w
.height
* 2;
254 if ((try_crop
.width
/win
->w
.width
) >= 2)
255 try_crop
.width
= win
->w
.width
* 2;
257 if (try_crop
.width
> 768) {
258 /* The OMAP2420 vertical resizing line buffer is
259 * 768 pixels wide. If the cropped image is wider
260 * than 768 pixels then it cannot be vertically resized.
262 if (try_crop
.height
!= win
->w
.height
)
263 try_crop
.width
= 768;
265 } else if (omap_vout_dss_omap34xx()) {
266 if ((try_crop
.height
/win
->w
.height
) >= 4)
267 try_crop
.height
= win
->w
.height
* 4;
269 if ((try_crop
.width
/win
->w
.width
) >= 4)
270 try_crop
.width
= win
->w
.width
* 4;
272 /* update our cropping rectangle and we're done */
276 EXPORT_SYMBOL_GPL(omap_vout_new_crop
);
278 /* Given a new format in pix and fbuf, crop and win
279 * structures are initialized to default values. crop
280 * is initialized to the largest window size that will fit on the display. The
281 * crop window is centered in the image. win is initialized to
282 * the same size as crop and is centered on the display.
283 * All sizes and offsets are constrained to be even numbers.
285 void omap_vout_new_format(struct v4l2_pix_format
*pix
,
286 struct v4l2_framebuffer
*fbuf
, struct v4l2_rect
*crop
,
287 struct v4l2_window
*win
)
289 /* crop defines the preview source window in the image capture
292 omap_vout_default_crop(pix
, fbuf
, crop
);
294 /* win defines the preview target window on the display */
295 win
->w
.width
= crop
->width
;
296 win
->w
.height
= crop
->height
;
297 win
->w
.left
= ((fbuf
->fmt
.width
- win
->w
.width
) >> 1) & ~1;
298 win
->w
.top
= ((fbuf
->fmt
.height
- win
->w
.height
) >> 1) & ~1;
300 EXPORT_SYMBOL_GPL(omap_vout_new_format
);
305 unsigned long omap_vout_alloc_buffer(u32 buf_size
, u32
*phys_addr
)
308 unsigned long virt_addr
, addr
;
310 size
= PAGE_ALIGN(buf_size
);
311 order
= get_order(size
);
312 virt_addr
= __get_free_pages(GFP_KERNEL
, order
);
317 SetPageReserved(virt_to_page(addr
));
322 *phys_addr
= (u32
) virt_to_phys((void *) virt_addr
);
329 void omap_vout_free_buffer(unsigned long virtaddr
, u32 buf_size
)
332 unsigned long addr
= virtaddr
;
334 size
= PAGE_ALIGN(buf_size
);
335 order
= get_order(size
);
338 ClearPageReserved(virt_to_page(addr
));
342 free_pages((unsigned long) virtaddr
, order
);
345 bool omap_vout_dss_omap24xx(void)
347 return omapdss_get_version() == OMAPDSS_VER_OMAP24xx
;
350 bool omap_vout_dss_omap34xx(void)
352 switch (omapdss_get_version()) {
353 case OMAPDSS_VER_OMAP34xx_ES1
:
354 case OMAPDSS_VER_OMAP34xx_ES3
:
355 case OMAPDSS_VER_OMAP3630
:
356 case OMAPDSS_VER_AM35xx
: