1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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>
26
27#include <linux/dma-mapping.h>
28
29#include <video/omapfb_dss.h>
30
31#include "omap_voutlib.h"
32
33MODULE_AUTHOR("Texas Instruments");
34MODULE_DESCRIPTION("OMAP Video library");
35MODULE_LICENSE("GPL");
36
37
38
39
40
41
42
43void omap_vout_default_crop(struct v4l2_pix_format *pix,
44 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
45{
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;
50 crop->width &= ~1;
51 crop->height &= ~1;
52 crop->left = ((pix->width - crop->width) >> 1) & ~1;
53 crop->top = ((pix->height - crop->height) >> 1) & ~1;
54}
55EXPORT_SYMBOL_GPL(omap_vout_default_crop);
56
57
58
59
60
61
62
63int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
64 struct v4l2_window *new_win)
65{
66 struct v4l2_rect try_win;
67
68
69 try_win = new_win->w;
70
71
72
73
74 if (try_win.left < 0) {
75 try_win.width += try_win.left;
76 try_win.left = 0;
77 }
78 if (try_win.top < 0) {
79 try_win.height += try_win.top;
80 try_win.top = 0;
81 }
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;
90 try_win.width &= ~1;
91 try_win.height &= ~1;
92
93 if (try_win.width <= 0 || try_win.height <= 0)
94 return -EINVAL;
95
96
97 new_win->w = try_win;
98 new_win->field = V4L2_FIELD_ANY;
99 return 0;
100}
101EXPORT_SYMBOL_GPL(omap_vout_try_window);
102
103
104
105
106
107
108
109
110
111int omap_vout_new_window(struct v4l2_rect *crop,
112 struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
113 struct v4l2_window *new_win)
114{
115 int err;
116
117 err = omap_vout_try_window(fbuf, new_win);
118 if (err)
119 return err;
120
121
122 win->w = new_win->w;
123 win->field = new_win->field;
124 win->chromakey = new_win->chromakey;
125
126
127 if (omap_vout_dss_omap24xx()) {
128
129 if ((crop->height/win->w.height) >= 2)
130 crop->height = win->w.height * 2;
131
132 if ((crop->width/win->w.width) >= 2)
133 crop->width = win->w.width * 2;
134
135 if (crop->width > 768) {
136
137
138
139
140 if (crop->height != win->w.height)
141 crop->width = 768;
142 }
143 } else if (omap_vout_dss_omap34xx()) {
144
145 if ((crop->height/win->w.height) >= 4)
146 crop->height = win->w.height * 4;
147
148 if ((crop->width/win->w.width) >= 4)
149 crop->width = win->w.width * 4;
150 }
151 return 0;
152}
153EXPORT_SYMBOL_GPL(omap_vout_new_window);
154
155
156
157
158
159
160
161
162
163
164
165int 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)
168{
169 struct v4l2_rect try_crop;
170 unsigned long vresize, hresize;
171
172
173 try_crop = *new_crop;
174
175
176 if (try_crop.left < 0) {
177 try_crop.width += try_crop.left;
178 try_crop.left = 0;
179 }
180 if (try_crop.top < 0) {
181 try_crop.height += try_crop.top;
182 try_crop.top = 0;
183 }
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;
192
193 try_crop.width &= ~1;
194 try_crop.height &= ~1;
195
196 if (try_crop.width <= 0 || try_crop.height <= 0)
197 return -EINVAL;
198
199 if (omap_vout_dss_omap24xx()) {
200 if (try_crop.height != win->w.height) {
201
202
203
204 if (try_crop.width > 768)
205 try_crop.width = 768;
206 }
207 }
208
209 vresize = (1024 * try_crop.height) / win->w.height;
210 if (omap_vout_dss_omap24xx() && (vresize > 2048))
211 vresize = 2048;
212 else if (omap_vout_dss_omap34xx() && (vresize > 4096))
213 vresize = 4096;
214
215 win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
216 if (win->w.height == 0)
217 win->w.height = 2;
218 if (win->w.height + win->w.top > fbuf->fmt.height) {
219
220
221
222
223 win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
224 if (try_crop.height == 0)
225 try_crop.height = 2;
226 }
227
228 hresize = (1024 * try_crop.width) / win->w.width;
229 if (omap_vout_dss_omap24xx() && (hresize > 2048))
230 hresize = 2048;
231 else if (omap_vout_dss_omap34xx() && (hresize > 4096))
232 hresize = 4096;
233
234 win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
235 if (win->w.width == 0)
236 win->w.width = 2;
237 if (win->w.width + win->w.left > fbuf->fmt.width) {
238
239
240
241
242 win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
243 if (try_crop.width == 0)
244 try_crop.width = 2;
245 }
246 if (omap_vout_dss_omap24xx()) {
247 if ((try_crop.height/win->w.height) >= 2)
248 try_crop.height = win->w.height * 2;
249
250 if ((try_crop.width/win->w.width) >= 2)
251 try_crop.width = win->w.width * 2;
252
253 if (try_crop.width > 768) {
254
255
256
257
258 if (try_crop.height != win->w.height)
259 try_crop.width = 768;
260 }
261 } else if (omap_vout_dss_omap34xx()) {
262 if ((try_crop.height/win->w.height) >= 4)
263 try_crop.height = win->w.height * 4;
264
265 if ((try_crop.width/win->w.width) >= 4)
266 try_crop.width = win->w.width * 4;
267 }
268
269 *crop = try_crop;
270 return 0;
271}
272EXPORT_SYMBOL_GPL(omap_vout_new_crop);
273
274
275
276
277
278
279
280
281void omap_vout_new_format(struct v4l2_pix_format *pix,
282 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
283 struct v4l2_window *win)
284{
285
286
287
288 omap_vout_default_crop(pix, fbuf, crop);
289
290
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;
295}
296EXPORT_SYMBOL_GPL(omap_vout_new_format);
297
298
299
300
301unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
302{
303 u32 order, size;
304 unsigned long virt_addr, addr;
305
306 size = PAGE_ALIGN(buf_size);
307 order = get_order(size);
308 virt_addr = __get_free_pages(GFP_KERNEL, order);
309 addr = virt_addr;
310
311 if (virt_addr) {
312 while (size > 0) {
313 SetPageReserved(virt_to_page(addr));
314 addr += PAGE_SIZE;
315 size -= PAGE_SIZE;
316 }
317 }
318 *phys_addr = (u32) virt_to_phys((void *) virt_addr);
319 return virt_addr;
320}
321
322
323
324
325void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
326{
327 u32 order, size;
328 unsigned long addr = virtaddr;
329
330 size = PAGE_ALIGN(buf_size);
331 order = get_order(size);
332
333 while (size > 0) {
334 ClearPageReserved(virt_to_page(addr));
335 addr += PAGE_SIZE;
336 size -= PAGE_SIZE;
337 }
338 free_pages((unsigned long) virtaddr, order);
339}
340
341bool omap_vout_dss_omap24xx(void)
342{
343 return omapdss_get_version() == OMAPDSS_VER_OMAP24xx;
344}
345
346bool omap_vout_dss_omap34xx(void)
347{
348 switch (omapdss_get_version()) {
349 case OMAPDSS_VER_OMAP34xx_ES1:
350 case OMAPDSS_VER_OMAP34xx_ES3:
351 case OMAPDSS_VER_OMAP3630:
352 case OMAPDSS_VER_AM35xx:
353 return true;
354 default:
355 return false;
356 }
357}
358