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>
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_ANY
;
101 EXPORT_SYMBOL_GPL(omap_vout_try_window
);
103 /* Given a new render window in new_win, adjust the window to the
104 * nearest supported configuration. The image cropping window in crop
105 * will also be adjusted if necessary. Preference is given to keeping the
106 * the window as close to the requested configuration as possible. If
107 * successful, new_win, vout->win, and crop are updated.
108 * Returns zero if successful, or -EINVAL if the requested preview window is
109 * impossible and cannot reasonably be adjusted.
111 int omap_vout_new_window(struct v4l2_rect
*crop
,
112 struct v4l2_window
*win
, struct v4l2_framebuffer
*fbuf
,
113 struct v4l2_window
*new_win
)
117 err
= omap_vout_try_window(fbuf
, new_win
);
121 /* update our preview window */
123 win
->field
= new_win
->field
;
124 win
->chromakey
= new_win
->chromakey
;
126 /* Adjust the cropping window to allow for resizing limitation */
127 if (cpu_is_omap24xx()) {
128 /* For 24xx limit is 8x to 1/2x scaling. */
129 if ((crop
->height
/win
->w
.height
) >= 2)
130 crop
->height
= win
->w
.height
* 2;
132 if ((crop
->width
/win
->w
.width
) >= 2)
133 crop
->width
= win
->w
.width
* 2;
135 if (crop
->width
> 768) {
136 /* The OMAP2420 vertical resizing line buffer is 768
137 * pixels wide. If the cropped image is wider than
138 * 768 pixels then it cannot be vertically resized.
140 if (crop
->height
!= win
->w
.height
)
143 } else if (cpu_is_omap34xx()) {
144 /* For 34xx limit is 8x to 1/4x scaling. */
145 if ((crop
->height
/win
->w
.height
) >= 4)
146 crop
->height
= win
->w
.height
* 4;
148 if ((crop
->width
/win
->w
.width
) >= 4)
149 crop
->width
= win
->w
.width
* 4;
153 EXPORT_SYMBOL_GPL(omap_vout_new_window
);
155 /* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
156 * the nearest supported configuration. The image render window in win will
157 * also be adjusted if necessary. The preview window is adjusted such that the
158 * horizontal and vertical rescaling ratios stay constant. If the render
159 * window would fall outside the display boundaries, the cropping rectangle
160 * will also be adjusted to maintain the rescaling ratios. If successful, crop
161 * and win are updated.
162 * Returns zero if successful, or -EINVAL if the requested cropping rectangle is
163 * impossible and cannot reasonably be adjusted.
165 int omap_vout_new_crop(struct v4l2_pix_format
*pix
,
166 struct v4l2_rect
*crop
, struct v4l2_window
*win
,
167 struct v4l2_framebuffer
*fbuf
, const struct v4l2_rect
*new_crop
)
169 struct v4l2_rect try_crop
;
170 unsigned long vresize
, hresize
;
172 /* make a working copy of the new_crop rectangle */
173 try_crop
= *new_crop
;
175 /* adjust the cropping rectangle so it fits in the image */
176 if (try_crop
.left
< 0) {
177 try_crop
.width
+= try_crop
.left
;
180 if (try_crop
.top
< 0) {
181 try_crop
.height
+= try_crop
.top
;
184 try_crop
.width
= (try_crop
.width
< pix
->width
) ?
185 try_crop
.width
: pix
->width
;
186 try_crop
.height
= (try_crop
.height
< pix
->height
) ?
187 try_crop
.height
: pix
->height
;
188 if (try_crop
.left
+ try_crop
.width
> pix
->width
)
189 try_crop
.width
= pix
->width
- try_crop
.left
;
190 if (try_crop
.top
+ try_crop
.height
> pix
->height
)
191 try_crop
.height
= pix
->height
- try_crop
.top
;
193 try_crop
.width
&= ~1;
194 try_crop
.height
&= ~1;
196 if (try_crop
.width
<= 0 || try_crop
.height
<= 0)
199 if (cpu_is_omap24xx()) {
200 if (try_crop
.height
!= win
->w
.height
) {
201 /* If we're resizing vertically, we can't support a
202 * crop width wider than 768 pixels.
204 if (try_crop
.width
> 768)
205 try_crop
.width
= 768;
208 /* vertical resizing */
209 vresize
= (1024 * try_crop
.height
) / win
->w
.height
;
210 if (cpu_is_omap24xx() && (vresize
> 2048))
212 else if (cpu_is_omap34xx() && (vresize
> 4096))
215 win
->w
.height
= ((1024 * try_crop
.height
) / vresize
) & ~1;
216 if (win
->w
.height
== 0)
218 if (win
->w
.height
+ win
->w
.top
> fbuf
->fmt
.height
) {
219 /* We made the preview window extend below the bottom of the
220 * display, so clip it to the display boundary and resize the
221 * cropping height to maintain the vertical resizing ratio.
223 win
->w
.height
= (fbuf
->fmt
.height
- win
->w
.top
) & ~1;
224 if (try_crop
.height
== 0)
227 /* horizontal resizing */
228 hresize
= (1024 * try_crop
.width
) / win
->w
.width
;
229 if (cpu_is_omap24xx() && (hresize
> 2048))
231 else if (cpu_is_omap34xx() && (hresize
> 4096))
234 win
->w
.width
= ((1024 * try_crop
.width
) / hresize
) & ~1;
235 if (win
->w
.width
== 0)
237 if (win
->w
.width
+ win
->w
.left
> fbuf
->fmt
.width
) {
238 /* We made the preview window extend past the right side of the
239 * display, so clip it to the display boundary and resize the
240 * cropping width to maintain the horizontal resizing ratio.
242 win
->w
.width
= (fbuf
->fmt
.width
- win
->w
.left
) & ~1;
243 if (try_crop
.width
== 0)
246 if (cpu_is_omap24xx()) {
247 if ((try_crop
.height
/win
->w
.height
) >= 2)
248 try_crop
.height
= win
->w
.height
* 2;
250 if ((try_crop
.width
/win
->w
.width
) >= 2)
251 try_crop
.width
= win
->w
.width
* 2;
253 if (try_crop
.width
> 768) {
254 /* The OMAP2420 vertical resizing line buffer is
255 * 768 pixels wide. If the cropped image is wider
256 * than 768 pixels then it cannot be vertically resized.
258 if (try_crop
.height
!= win
->w
.height
)
259 try_crop
.width
= 768;
261 } else if (cpu_is_omap34xx()) {
262 if ((try_crop
.height
/win
->w
.height
) >= 4)
263 try_crop
.height
= win
->w
.height
* 4;
265 if ((try_crop
.width
/win
->w
.width
) >= 4)
266 try_crop
.width
= win
->w
.width
* 4;
268 /* update our cropping rectangle and we're done */
272 EXPORT_SYMBOL_GPL(omap_vout_new_crop
);
274 /* Given a new format in pix and fbuf, crop and win
275 * structures are initialized to default values. crop
276 * is initialized to the largest window size that will fit on the display. The
277 * crop window is centered in the image. win is initialized to
278 * the same size as crop and is centered on the display.
279 * All sizes and offsets are constrained to be even numbers.
281 void omap_vout_new_format(struct v4l2_pix_format
*pix
,
282 struct v4l2_framebuffer
*fbuf
, struct v4l2_rect
*crop
,
283 struct v4l2_window
*win
)
285 /* crop defines the preview source window in the image capture
288 omap_vout_default_crop(pix
, fbuf
, crop
);
290 /* win defines the preview target window on the display */
291 win
->w
.width
= crop
->width
;
292 win
->w
.height
= crop
->height
;
293 win
->w
.left
= ((fbuf
->fmt
.width
- win
->w
.width
) >> 1) & ~1;
294 win
->w
.top
= ((fbuf
->fmt
.height
- win
->w
.height
) >> 1) & ~1;
296 EXPORT_SYMBOL_GPL(omap_vout_new_format
);
301 unsigned long omap_vout_alloc_buffer(u32 buf_size
, u32
*phys_addr
)
304 unsigned long virt_addr
, addr
;
306 size
= PAGE_ALIGN(buf_size
);
307 order
= get_order(size
);
308 virt_addr
= __get_free_pages(GFP_KERNEL
, order
);
313 SetPageReserved(virt_to_page(addr
));
318 *phys_addr
= (u32
) virt_to_phys((void *) virt_addr
);
325 void omap_vout_free_buffer(unsigned long virtaddr
, u32 buf_size
)
328 unsigned long addr
= virtaddr
;
330 size
= PAGE_ALIGN(buf_size
);
331 order
= get_order(size
);
334 ClearPageReserved(virt_to_page(addr
));
338 free_pages((unsigned long) virtaddr
, order
);