diff options
author | archit taneja <archit@ti.com> | 2011-06-14 02:54:47 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-27 16:56:06 -0400 |
commit | 445e258fa286cb83818b731ef4075a8cc183f2f3 (patch) | |
tree | cf76fc42c53bab44c76e012cc8635b01a1ab0017 /drivers/media/video/omap | |
parent | b366888a9020f933bdab8f15f8d4a63e988ce6b3 (diff) |
[media] OMAP_VOUT: Create separate file for VRFB related API's
Introduce omap_vout_vrfb.c and omap_vout_vrfb.h, for all VRFB related API's,
making OMAP_VOUT driver independent from VRFB. This is required for OMAP4 DSS,
since OMAP4 doesn't have VRFB block.
Added new enum vout_rotation_type and "rotation_type" member to omapvideo_info,
this is initialized based on the arch type in omap_vout_probe. The rotation_type
var is now used to choose between vrfb and non-vrfb calls.
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/omap')
-rw-r--r-- | drivers/media/video/omap/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/video/omap/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/video/omap/omap_vout.c | 455 | ||||
-rw-r--r-- | drivers/media/video/omap/omap_vout_vrfb.c | 390 | ||||
-rw-r--r-- | drivers/media/video/omap/omap_vout_vrfb.h | 40 | ||||
-rw-r--r-- | drivers/media/video/omap/omap_voutdef.h | 16 |
6 files changed, 537 insertions, 372 deletions
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig index e63233fd2aaa..390ab094f9f2 100644 --- a/drivers/media/video/omap/Kconfig +++ b/drivers/media/video/omap/Kconfig | |||
@@ -1,11 +1,14 @@ | |||
1 | config VIDEO_OMAP2_VOUT_VRFB | ||
2 | bool | ||
3 | |||
1 | config VIDEO_OMAP2_VOUT | 4 | config VIDEO_OMAP2_VOUT |
2 | tristate "OMAP2/OMAP3 V4L2-Display driver" | 5 | tristate "OMAP2/OMAP3 V4L2-Display driver" |
3 | depends on ARCH_OMAP2 || ARCH_OMAP3 | 6 | depends on ARCH_OMAP2 || ARCH_OMAP3 |
4 | select VIDEOBUF_GEN | 7 | select VIDEOBUF_GEN |
5 | select VIDEOBUF_DMA_CONTIG | 8 | select VIDEOBUF_DMA_CONTIG |
6 | select OMAP2_DSS | 9 | select OMAP2_DSS |
7 | select OMAP2_VRAM | 10 | select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 |
8 | select OMAP2_VRFB | 11 | select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB |
9 | default n | 12 | default n |
10 | ---help--- | 13 | ---help--- |
11 | V4L2 Display driver support for OMAP2/3 based boards. | 14 | V4L2 Display driver support for OMAP2/3 based boards. |
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile index b28788070ae1..fc410b438f7d 100644 --- a/drivers/media/video/omap/Makefile +++ b/drivers/media/video/omap/Makefile | |||
@@ -4,4 +4,5 @@ | |||
4 | 4 | ||
5 | # OMAP2/3 Display driver | 5 | # OMAP2/3 Display driver |
6 | omap-vout-y := omap_vout.o omap_voutlib.o | 6 | omap-vout-y := omap_vout.o omap_voutlib.o |
7 | omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o | ||
7 | obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o | 8 | obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o |
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 8d69f287ad08..56b22b9356a5 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c | |||
@@ -48,6 +48,7 @@ | |||
48 | 48 | ||
49 | #include "omap_voutlib.h" | 49 | #include "omap_voutlib.h" |
50 | #include "omap_voutdef.h" | 50 | #include "omap_voutdef.h" |
51 | #include "omap_vout_vrfb.h" | ||
51 | 52 | ||
52 | MODULE_AUTHOR("Texas Instruments"); | 53 | MODULE_AUTHOR("Texas Instruments"); |
53 | MODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); | 54 | MODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); |
@@ -143,41 +144,6 @@ static const struct v4l2_fmtdesc omap_formats[] = { | |||
143 | #define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) | 144 | #define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) |
144 | 145 | ||
145 | /* | 146 | /* |
146 | * Function for allocating video buffers | ||
147 | */ | ||
148 | static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, | ||
149 | unsigned int *count, int startindex) | ||
150 | { | ||
151 | int i, j; | ||
152 | |||
153 | for (i = 0; i < *count; i++) { | ||
154 | if (!vout->smsshado_virt_addr[i]) { | ||
155 | vout->smsshado_virt_addr[i] = | ||
156 | omap_vout_alloc_buffer(vout->smsshado_size, | ||
157 | &vout->smsshado_phy_addr[i]); | ||
158 | } | ||
159 | if (!vout->smsshado_virt_addr[i] && startindex != -1) { | ||
160 | if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex) | ||
161 | break; | ||
162 | } | ||
163 | if (!vout->smsshado_virt_addr[i]) { | ||
164 | for (j = 0; j < i; j++) { | ||
165 | omap_vout_free_buffer( | ||
166 | vout->smsshado_virt_addr[j], | ||
167 | vout->smsshado_size); | ||
168 | vout->smsshado_virt_addr[j] = 0; | ||
169 | vout->smsshado_phy_addr[j] = 0; | ||
170 | } | ||
171 | *count = 0; | ||
172 | return -ENOMEM; | ||
173 | } | ||
174 | memset((void *) vout->smsshado_virt_addr[i], 0, | ||
175 | vout->smsshado_size); | ||
176 | } | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Try format | 147 | * Try format |
182 | */ | 148 | */ |
183 | static int omap_vout_try_format(struct v4l2_pix_format *pix) | 149 | static int omap_vout_try_format(struct v4l2_pix_format *pix) |
@@ -270,36 +236,9 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp) | |||
270 | } | 236 | } |
271 | 237 | ||
272 | /* | 238 | /* |
273 | * Wakes up the application once the DMA transfer to VRFB space is completed. | ||
274 | */ | ||
275 | static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data) | ||
276 | { | ||
277 | struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data; | ||
278 | |||
279 | t->tx_status = 1; | ||
280 | wake_up_interruptible(&t->wait); | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Release the VRFB context once the module exits | ||
285 | */ | ||
286 | static void omap_vout_release_vrfb(struct omap_vout_device *vout) | ||
287 | { | ||
288 | int i; | ||
289 | |||
290 | for (i = 0; i < VRFB_NUM_BUFS; i++) | ||
291 | omap_vrfb_release_ctx(&vout->vrfb_context[i]); | ||
292 | |||
293 | if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) { | ||
294 | vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; | ||
295 | omap_free_dma(vout->vrfb_dma_tx.dma_ch); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Free the V4L2 buffers | 239 | * Free the V4L2 buffers |
301 | */ | 240 | */ |
302 | static void omap_vout_free_buffers(struct omap_vout_device *vout) | 241 | void omap_vout_free_buffers(struct omap_vout_device *vout) |
303 | { | 242 | { |
304 | int i, numbuffers; | 243 | int i, numbuffers; |
305 | 244 | ||
@@ -316,52 +255,6 @@ static void omap_vout_free_buffers(struct omap_vout_device *vout) | |||
316 | } | 255 | } |
317 | 256 | ||
318 | /* | 257 | /* |
319 | * Free VRFB buffers | ||
320 | */ | ||
321 | static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) | ||
322 | { | ||
323 | int j; | ||
324 | |||
325 | for (j = 0; j < VRFB_NUM_BUFS; j++) { | ||
326 | omap_vout_free_buffer(vout->smsshado_virt_addr[j], | ||
327 | vout->smsshado_size); | ||
328 | vout->smsshado_virt_addr[j] = 0; | ||
329 | vout->smsshado_phy_addr[j] = 0; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Allocate the buffers for the VRFB space. Data is copied from V4L2 | ||
335 | * buffers to the VRFB buffers using the DMA engine. | ||
336 | */ | ||
337 | static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, | ||
338 | unsigned int *count, unsigned int startindex) | ||
339 | { | ||
340 | int i; | ||
341 | bool yuv_mode; | ||
342 | |||
343 | /* Allocate the VRFB buffers only if the buffers are not | ||
344 | * allocated during init time. | ||
345 | */ | ||
346 | if ((is_rotation_enabled(vout)) && !vout->vrfb_static_allocation) | ||
347 | if (omap_vout_allocate_vrfb_buffers(vout, count, startindex)) | ||
348 | return -ENOMEM; | ||
349 | |||
350 | if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 || | ||
351 | vout->dss_mode == OMAP_DSS_COLOR_UYVY) | ||
352 | yuv_mode = true; | ||
353 | else | ||
354 | yuv_mode = false; | ||
355 | |||
356 | for (i = 0; i < *count; i++) | ||
357 | omap_vrfb_setup(&vout->vrfb_context[i], | ||
358 | vout->smsshado_phy_addr[i], vout->pix.width, | ||
359 | vout->pix.height, vout->bpp, yuv_mode); | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Convert V4L2 rotation to DSS rotation | 258 | * Convert V4L2 rotation to DSS rotation |
366 | * V4L2 understand 0, 90, 180, 270. | 259 | * V4L2 understand 0, 90, 180, 270. |
367 | * Convert to 0, 1, 2 and 3 respectively for DSS | 260 | * Convert to 0, 1, 2 and 3 respectively for DSS |
@@ -390,124 +283,38 @@ static int v4l2_rot_to_dss_rot(int v4l2_rotation, | |||
390 | return ret; | 283 | return ret; |
391 | } | 284 | } |
392 | 285 | ||
393 | /* | ||
394 | * Calculate the buffer offsets from which the streaming should | ||
395 | * start. This offset calculation is mainly required because of | ||
396 | * the VRFB 32 pixels alignment with rotation. | ||
397 | */ | ||
398 | static int omap_vout_calculate_offset(struct omap_vout_device *vout) | 286 | static int omap_vout_calculate_offset(struct omap_vout_device *vout) |
399 | { | 287 | { |
400 | struct omap_overlay *ovl; | ||
401 | enum dss_rotation rotation; | ||
402 | struct omapvideo_info *ovid; | 288 | struct omapvideo_info *ovid; |
403 | bool mirroring = vout->mirror; | ||
404 | struct omap_dss_device *cur_display; | ||
405 | struct v4l2_rect *crop = &vout->crop; | 289 | struct v4l2_rect *crop = &vout->crop; |
406 | struct v4l2_pix_format *pix = &vout->pix; | 290 | struct v4l2_pix_format *pix = &vout->pix; |
407 | int *cropped_offset = &vout->cropped_offset; | 291 | int *cropped_offset = &vout->cropped_offset; |
408 | int vr_ps = 1, ps = 2, temp_ps = 2; | 292 | int ps = 2, line_length = 0; |
409 | int offset = 0, ctop = 0, cleft = 0, line_length = 0; | ||
410 | 293 | ||
411 | ovid = &vout->vid_info; | 294 | ovid = &vout->vid_info; |
412 | ovl = ovid->overlays[0]; | ||
413 | /* get the display device attached to the overlay */ | ||
414 | if (!ovl->manager || !ovl->manager->device) | ||
415 | return -1; | ||
416 | 295 | ||
417 | cur_display = ovl->manager->device; | 296 | if (ovid->rotation_type == VOUT_ROT_VRFB) { |
418 | rotation = calc_rotation(vout); | 297 | omap_vout_calculate_vrfb_offset(vout); |
298 | } else { | ||
299 | vout->line_length = line_length = pix->width; | ||
419 | 300 | ||
420 | if (V4L2_PIX_FMT_YUYV == pix->pixelformat || | 301 | if (V4L2_PIX_FMT_YUYV == pix->pixelformat || |
421 | V4L2_PIX_FMT_UYVY == pix->pixelformat) { | 302 | V4L2_PIX_FMT_UYVY == pix->pixelformat) |
422 | if (is_rotation_enabled(vout)) { | 303 | ps = 2; |
423 | /* | 304 | else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) |
424 | * ps - Actual pixel size for YUYV/UYVY for | ||
425 | * VRFB/Mirroring is 4 bytes | ||
426 | * vr_ps - Virtually pixel size for YUYV/UYVY is | ||
427 | * 2 bytes | ||
428 | */ | ||
429 | ps = 4; | 305 | ps = 4; |
430 | vr_ps = 2; | 306 | else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) |
431 | } else { | 307 | ps = 3; |
432 | ps = 2; /* otherwise the pixel size is 2 byte */ | ||
433 | } | ||
434 | } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) { | ||
435 | ps = 4; | ||
436 | } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) { | ||
437 | ps = 3; | ||
438 | } | ||
439 | vout->ps = ps; | ||
440 | vout->vr_ps = vr_ps; | ||
441 | |||
442 | if (is_rotation_enabled(vout)) { | ||
443 | line_length = MAX_PIXELS_PER_LINE; | ||
444 | ctop = (pix->height - crop->height) - crop->top; | ||
445 | cleft = (pix->width - crop->width) - crop->left; | ||
446 | } else { | ||
447 | line_length = pix->width; | ||
448 | } | ||
449 | vout->line_length = line_length; | ||
450 | switch (rotation) { | ||
451 | case dss_rotation_90_degree: | ||
452 | offset = vout->vrfb_context[0].yoffset * | ||
453 | vout->vrfb_context[0].bytespp; | ||
454 | temp_ps = ps / vr_ps; | ||
455 | if (mirroring == 0) { | ||
456 | *cropped_offset = offset + line_length * | ||
457 | temp_ps * cleft + crop->top * temp_ps; | ||
458 | } else { | ||
459 | *cropped_offset = offset + line_length * temp_ps * | ||
460 | cleft + crop->top * temp_ps + (line_length * | ||
461 | ((crop->width / (vr_ps)) - 1) * ps); | ||
462 | } | ||
463 | break; | ||
464 | case dss_rotation_180_degree: | ||
465 | offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset * | ||
466 | vout->vrfb_context[0].bytespp) + | ||
467 | (vout->vrfb_context[0].xoffset * | ||
468 | vout->vrfb_context[0].bytespp)); | ||
469 | if (mirroring == 0) { | ||
470 | *cropped_offset = offset + (line_length * ps * ctop) + | ||
471 | (cleft / vr_ps) * ps; | ||
472 | 308 | ||
473 | } else { | 309 | vout->ps = ps; |
474 | *cropped_offset = offset + (line_length * ps * ctop) + | 310 | |
475 | (cleft / vr_ps) * ps + (line_length * | 311 | *cropped_offset = (line_length * ps) * |
476 | (crop->height - 1) * ps); | 312 | crop->top + crop->left * ps; |
477 | } | ||
478 | break; | ||
479 | case dss_rotation_270_degree: | ||
480 | offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset * | ||
481 | vout->vrfb_context[0].bytespp; | ||
482 | temp_ps = ps / vr_ps; | ||
483 | if (mirroring == 0) { | ||
484 | *cropped_offset = offset + line_length * | ||
485 | temp_ps * crop->left + ctop * ps; | ||
486 | } else { | ||
487 | *cropped_offset = offset + line_length * | ||
488 | temp_ps * crop->left + ctop * ps + | ||
489 | (line_length * ((crop->width / vr_ps) - 1) * | ||
490 | ps); | ||
491 | } | ||
492 | break; | ||
493 | case dss_rotation_0_degree: | ||
494 | if (mirroring == 0) { | ||
495 | *cropped_offset = (line_length * ps) * | ||
496 | crop->top + (crop->left / vr_ps) * ps; | ||
497 | } else { | ||
498 | *cropped_offset = (line_length * ps) * | ||
499 | crop->top + (crop->left / vr_ps) * ps + | ||
500 | (line_length * (crop->height - 1) * ps); | ||
501 | } | ||
502 | break; | ||
503 | default: | ||
504 | *cropped_offset = (line_length * ps * crop->top) / | ||
505 | vr_ps + (crop->left * ps) / vr_ps + | ||
506 | ((crop->width / vr_ps) - 1) * ps; | ||
507 | break; | ||
508 | } | 313 | } |
314 | |||
509 | v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n", | 315 | v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n", |
510 | __func__, *cropped_offset); | 316 | __func__, vout->cropped_offset); |
317 | |||
511 | return 0; | 318 | return 0; |
512 | } | 319 | } |
513 | 320 | ||
@@ -845,6 +652,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, | |||
845 | int startindex = 0, i, j; | 652 | int startindex = 0, i, j; |
846 | u32 phy_addr = 0, virt_addr = 0; | 653 | u32 phy_addr = 0, virt_addr = 0; |
847 | struct omap_vout_device *vout = q->priv_data; | 654 | struct omap_vout_device *vout = q->priv_data; |
655 | struct omapvideo_info *ovid = &vout->vid_info; | ||
848 | 656 | ||
849 | if (!vout) | 657 | if (!vout) |
850 | return -EINVAL; | 658 | return -EINVAL; |
@@ -857,13 +665,10 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, | |||
857 | if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) | 665 | if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) |
858 | *count = startindex; | 666 | *count = startindex; |
859 | 667 | ||
860 | if ((is_rotation_enabled(vout)) && *count > VRFB_NUM_BUFS) | 668 | if (ovid->rotation_type == VOUT_ROT_VRFB) { |
861 | *count = VRFB_NUM_BUFS; | ||
862 | |||
863 | /* If rotation is enabled, allocate memory for VRFB space also */ | ||
864 | if (is_rotation_enabled(vout)) | ||
865 | if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) | 669 | if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) |
866 | return -ENOMEM; | 670 | return -ENOMEM; |
671 | } | ||
867 | 672 | ||
868 | if (V4L2_MEMORY_MMAP != vout->memory) | 673 | if (V4L2_MEMORY_MMAP != vout->memory) |
869 | return 0; | 674 | return 0; |
@@ -887,8 +692,11 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, | |||
887 | virt_addr = omap_vout_alloc_buffer(vout->buffer_size, | 692 | virt_addr = omap_vout_alloc_buffer(vout->buffer_size, |
888 | &phy_addr); | 693 | &phy_addr); |
889 | if (!virt_addr) { | 694 | if (!virt_addr) { |
890 | if (!is_rotation_enabled(vout)) | 695 | if (ovid->rotation_type == VOUT_ROT_NONE) { |
891 | break; | 696 | break; |
697 | } else { | ||
698 | if (!is_rotation_enabled(vout)) | ||
699 | break; | ||
892 | /* Free the VRFB buffers if no space for V4L2 buffers */ | 700 | /* Free the VRFB buffers if no space for V4L2 buffers */ |
893 | for (j = i; j < *count; j++) { | 701 | for (j = i; j < *count; j++) { |
894 | omap_vout_free_buffer( | 702 | omap_vout_free_buffer( |
@@ -896,6 +704,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, | |||
896 | vout->smsshado_size); | 704 | vout->smsshado_size); |
897 | vout->smsshado_virt_addr[j] = 0; | 705 | vout->smsshado_virt_addr[j] = 0; |
898 | vout->smsshado_phy_addr[j] = 0; | 706 | vout->smsshado_phy_addr[j] = 0; |
707 | } | ||
899 | } | 708 | } |
900 | } | 709 | } |
901 | vout->buf_virt_addr[i] = virt_addr; | 710 | vout->buf_virt_addr[i] = virt_addr; |
@@ -908,9 +717,9 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, | |||
908 | 717 | ||
909 | /* | 718 | /* |
910 | * Free the V4L2 buffers additionally allocated than default | 719 | * Free the V4L2 buffers additionally allocated than default |
911 | * number of buffers and free all the VRFB buffers | 720 | * number of buffers |
912 | */ | 721 | */ |
913 | static void omap_vout_free_allbuffers(struct omap_vout_device *vout) | 722 | static void omap_vout_free_extra_buffers(struct omap_vout_device *vout) |
914 | { | 723 | { |
915 | int num_buffers = 0, i; | 724 | int num_buffers = 0, i; |
916 | 725 | ||
@@ -925,20 +734,6 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout) | |||
925 | vout->buf_virt_addr[i] = 0; | 734 | vout->buf_virt_addr[i] = 0; |
926 | vout->buf_phy_addr[i] = 0; | 735 | vout->buf_phy_addr[i] = 0; |
927 | } | 736 | } |
928 | /* Free the VRFB buffers only if they are allocated | ||
929 | * during reqbufs. Don't free if init time allocated | ||
930 | */ | ||
931 | if (!vout->vrfb_static_allocation) { | ||
932 | for (i = 0; i < VRFB_NUM_BUFS; i++) { | ||
933 | if (vout->smsshado_virt_addr[i]) { | ||
934 | omap_vout_free_buffer( | ||
935 | vout->smsshado_virt_addr[i], | ||
936 | vout->smsshado_size); | ||
937 | vout->smsshado_virt_addr[i] = 0; | ||
938 | vout->smsshado_phy_addr[i] = 0; | ||
939 | } | ||
940 | } | ||
941 | } | ||
942 | vout->buffer_allocated = num_buffers; | 737 | vout->buffer_allocated = num_buffers; |
943 | } | 738 | } |
944 | 739 | ||
@@ -950,16 +745,11 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout) | |||
950 | * buffer into VRFB memory space before giving it to the DSS. | 745 | * buffer into VRFB memory space before giving it to the DSS. |
951 | */ | 746 | */ |
952 | static int omap_vout_buffer_prepare(struct videobuf_queue *q, | 747 | static int omap_vout_buffer_prepare(struct videobuf_queue *q, |
953 | struct videobuf_buffer *vb, | 748 | struct videobuf_buffer *vb, |
954 | enum v4l2_field field) | 749 | enum v4l2_field field) |
955 | { | 750 | { |
956 | dma_addr_t dmabuf; | ||
957 | struct vid_vrfb_dma *tx; | ||
958 | enum dss_rotation rotation; | ||
959 | struct omap_vout_device *vout = q->priv_data; | 751 | struct omap_vout_device *vout = q->priv_data; |
960 | u32 dest_frame_index = 0, src_element_index = 0; | 752 | struct omapvideo_info *ovid = &vout->vid_info; |
961 | u32 dest_element_index = 0, src_frame_index = 0; | ||
962 | u32 elem_count = 0, frame_count = 0, pixsize = 2; | ||
963 | 753 | ||
964 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | 754 | if (VIDEOBUF_NEEDS_INIT == vb->state) { |
965 | vb->width = vout->pix.width; | 755 | vb->width = vout->pix.width; |
@@ -981,63 +771,10 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, | |||
981 | vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; | 771 | vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; |
982 | } | 772 | } |
983 | 773 | ||
984 | if (!is_rotation_enabled(vout)) | 774 | if (ovid->rotation_type == VOUT_ROT_VRFB) |
775 | return omap_vout_prepare_vrfb(vout, vb); | ||
776 | else | ||
985 | return 0; | 777 | return 0; |
986 | |||
987 | dmabuf = vout->buf_phy_addr[vb->i]; | ||
988 | /* If rotation is enabled, copy input buffer into VRFB | ||
989 | * memory space using DMA. We are copying input buffer | ||
990 | * into VRFB memory space of desired angle and DSS will | ||
991 | * read image VRFB memory for 0 degree angle | ||
992 | */ | ||
993 | pixsize = vout->bpp * vout->vrfb_bpp; | ||
994 | /* | ||
995 | * DMA transfer in double index mode | ||
996 | */ | ||
997 | |||
998 | /* Frame index */ | ||
999 | dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) - | ||
1000 | (vout->pix.width * vout->bpp)) + 1; | ||
1001 | |||
1002 | /* Source and destination parameters */ | ||
1003 | src_element_index = 0; | ||
1004 | src_frame_index = 0; | ||
1005 | dest_element_index = 1; | ||
1006 | /* Number of elements per frame */ | ||
1007 | elem_count = vout->pix.width * vout->bpp; | ||
1008 | frame_count = vout->pix.height; | ||
1009 | tx = &vout->vrfb_dma_tx; | ||
1010 | tx->tx_status = 0; | ||
1011 | omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32, | ||
1012 | (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT, | ||
1013 | tx->dev_id, 0x0); | ||
1014 | /* src_port required only for OMAP1 */ | ||
1015 | omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, | ||
1016 | dmabuf, src_element_index, src_frame_index); | ||
1017 | /*set dma source burst mode for VRFB */ | ||
1018 | omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
1019 | rotation = calc_rotation(vout); | ||
1020 | |||
1021 | /* dest_port required only for OMAP1 */ | ||
1022 | omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX, | ||
1023 | vout->vrfb_context[vb->i].paddr[0], dest_element_index, | ||
1024 | dest_frame_index); | ||
1025 | /*set dma dest burst mode for VRFB */ | ||
1026 | omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
1027 | omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0); | ||
1028 | |||
1029 | omap_start_dma(tx->dma_ch); | ||
1030 | interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT); | ||
1031 | |||
1032 | if (tx->tx_status == 0) { | ||
1033 | omap_stop_dma(tx->dma_ch); | ||
1034 | return -EINVAL; | ||
1035 | } | ||
1036 | /* Store buffers physical address into an array. Addresses | ||
1037 | * from this array will be used to configure DSS */ | ||
1038 | vout->queued_buf_addr[vb->i] = (u8 *) | ||
1039 | vout->vrfb_context[vb->i].paddr[rotation]; | ||
1040 | return 0; | ||
1041 | } | 778 | } |
1042 | 779 | ||
1043 | /* | 780 | /* |
@@ -1189,7 +926,15 @@ static int omap_vout_release(struct file *file) | |||
1189 | "Unable to apply changes\n"); | 926 | "Unable to apply changes\n"); |
1190 | 927 | ||
1191 | /* Free all buffers */ | 928 | /* Free all buffers */ |
1192 | omap_vout_free_allbuffers(vout); | 929 | omap_vout_free_extra_buffers(vout); |
930 | |||
931 | /* Free the VRFB buffers only if they are allocated | ||
932 | * during reqbufs. Don't free if init time allocated | ||
933 | */ | ||
934 | if (ovid->rotation_type == VOUT_ROT_VRFB) { | ||
935 | if (!vout->vrfb_static_allocation) | ||
936 | omap_vout_free_vrfb_buffers(vout); | ||
937 | } | ||
1193 | videobuf_mmap_free(q); | 938 | videobuf_mmap_free(q); |
1194 | 939 | ||
1195 | /* Even if apply changes fails we should continue | 940 | /* Even if apply changes fails we should continue |
@@ -1616,9 +1361,17 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) | |||
1616 | switch (a->id) { | 1361 | switch (a->id) { |
1617 | case V4L2_CID_ROTATE: | 1362 | case V4L2_CID_ROTATE: |
1618 | { | 1363 | { |
1364 | struct omapvideo_info *ovid; | ||
1619 | int rotation = a->value; | 1365 | int rotation = a->value; |
1620 | 1366 | ||
1367 | ovid = &vout->vid_info; | ||
1368 | |||
1621 | mutex_lock(&vout->lock); | 1369 | mutex_lock(&vout->lock); |
1370 | if (rotation && ovid->rotation_type == VOUT_ROT_NONE) { | ||
1371 | mutex_unlock(&vout->lock); | ||
1372 | ret = -ERANGE; | ||
1373 | break; | ||
1374 | } | ||
1622 | 1375 | ||
1623 | if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { | 1376 | if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { |
1624 | mutex_unlock(&vout->lock); | 1377 | mutex_unlock(&vout->lock); |
@@ -1674,6 +1427,11 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) | |||
1674 | ovl = ovid->overlays[0]; | 1427 | ovl = ovid->overlays[0]; |
1675 | 1428 | ||
1676 | mutex_lock(&vout->lock); | 1429 | mutex_lock(&vout->lock); |
1430 | if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { | ||
1431 | mutex_unlock(&vout->lock); | ||
1432 | ret = -ERANGE; | ||
1433 | break; | ||
1434 | } | ||
1677 | 1435 | ||
1678 | if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { | 1436 | if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { |
1679 | mutex_unlock(&vout->lock); | 1437 | mutex_unlock(&vout->lock); |
@@ -2119,7 +1877,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) | |||
2119 | vout->mirror = 0; | 1877 | vout->mirror = 0; |
2120 | vout->control[2].id = V4L2_CID_HFLIP; | 1878 | vout->control[2].id = V4L2_CID_HFLIP; |
2121 | vout->control[2].value = 0; | 1879 | vout->control[2].value = 0; |
2122 | vout->vrfb_bpp = 2; | 1880 | if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) |
1881 | vout->vrfb_bpp = 2; | ||
2123 | 1882 | ||
2124 | control[1].id = V4L2_CID_BG_COLOR; | 1883 | control[1].id = V4L2_CID_BG_COLOR; |
2125 | control[1].value = 0; | 1884 | control[1].value = 0; |
@@ -2151,17 +1910,15 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, | |||
2151 | int vid_num) | 1910 | int vid_num) |
2152 | { | 1911 | { |
2153 | u32 numbuffers; | 1912 | u32 numbuffers; |
2154 | int ret = 0, i, j; | 1913 | int ret = 0, i; |
2155 | int image_width, image_height; | 1914 | struct omapvideo_info *ovid; |
2156 | struct video_device *vfd; | ||
2157 | struct omap_vout_device *vout; | 1915 | struct omap_vout_device *vout; |
2158 | int static_vrfb_allocation = 0, vrfb_num_bufs = VRFB_NUM_BUFS; | ||
2159 | struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); | 1916 | struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); |
2160 | struct omap2video_device *vid_dev = | 1917 | struct omap2video_device *vid_dev = |
2161 | container_of(v4l2_dev, struct omap2video_device, v4l2_dev); | 1918 | container_of(v4l2_dev, struct omap2video_device, v4l2_dev); |
2162 | 1919 | ||
2163 | vout = vid_dev->vouts[vid_num]; | 1920 | vout = vid_dev->vouts[vid_num]; |
2164 | vfd = vout->vfd; | 1921 | ovid = &vout->vid_info; |
2165 | 1922 | ||
2166 | numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; | 1923 | numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; |
2167 | vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; | 1924 | vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; |
@@ -2178,66 +1935,16 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, | |||
2178 | } | 1935 | } |
2179 | } | 1936 | } |
2180 | 1937 | ||
2181 | for (i = 0; i < VRFB_NUM_BUFS; i++) { | ||
2182 | if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { | ||
2183 | dev_info(&pdev->dev, ": VRFB allocation failed\n"); | ||
2184 | for (j = 0; j < i; j++) | ||
2185 | omap_vrfb_release_ctx(&vout->vrfb_context[j]); | ||
2186 | ret = -ENOMEM; | ||
2187 | goto free_buffers; | ||
2188 | } | ||
2189 | } | ||
2190 | vout->cropped_offset = 0; | 1938 | vout->cropped_offset = 0; |
2191 | 1939 | ||
2192 | /* Calculate VRFB memory size */ | 1940 | if (ovid->rotation_type == VOUT_ROT_VRFB) { |
2193 | /* allocate for worst case size */ | 1941 | int static_vrfb_allocation = (vid_num == 0) ? |
2194 | image_width = VID_MAX_WIDTH / TILE_SIZE; | 1942 | vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; |
2195 | if (VID_MAX_WIDTH % TILE_SIZE) | 1943 | ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, |
2196 | image_width++; | 1944 | static_vrfb_allocation); |
2197 | |||
2198 | image_width = image_width * TILE_SIZE; | ||
2199 | image_height = VID_MAX_HEIGHT / TILE_SIZE; | ||
2200 | |||
2201 | if (VID_MAX_HEIGHT % TILE_SIZE) | ||
2202 | image_height++; | ||
2203 | |||
2204 | image_height = image_height * TILE_SIZE; | ||
2205 | vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); | ||
2206 | |||
2207 | /* | ||
2208 | * Request and Initialize DMA, for DMA based VRFB transfer | ||
2209 | */ | ||
2210 | vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; | ||
2211 | vout->vrfb_dma_tx.dma_ch = -1; | ||
2212 | vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; | ||
2213 | ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", | ||
2214 | omap_vout_vrfb_dma_tx_callback, | ||
2215 | (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); | ||
2216 | if (ret < 0) { | ||
2217 | vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; | ||
2218 | dev_info(&pdev->dev, ": failed to allocate DMA Channel for" | ||
2219 | " video%d\n", vfd->minor); | ||
2220 | } | ||
2221 | init_waitqueue_head(&vout->vrfb_dma_tx.wait); | ||
2222 | |||
2223 | /* Allocate VRFB buffers if selected through bootargs */ | ||
2224 | static_vrfb_allocation = (vid_num == 0) ? | ||
2225 | vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; | ||
2226 | |||
2227 | /* statically allocated the VRFB buffer is done through | ||
2228 | commands line aruments */ | ||
2229 | if (static_vrfb_allocation) { | ||
2230 | if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { | ||
2231 | ret = -ENOMEM; | ||
2232 | goto release_vrfb_ctx; | ||
2233 | } | ||
2234 | vout->vrfb_static_allocation = 1; | ||
2235 | } | 1945 | } |
2236 | return 0; | ||
2237 | 1946 | ||
2238 | release_vrfb_ctx: | 1947 | return ret; |
2239 | for (j = 0; j < VRFB_NUM_BUFS; j++) | ||
2240 | omap_vrfb_release_ctx(&vout->vrfb_context[j]); | ||
2241 | 1948 | ||
2242 | free_buffers: | 1949 | free_buffers: |
2243 | for (i = 0; i < numbuffers; i++) { | 1950 | for (i = 0; i < numbuffers; i++) { |
@@ -2280,6 +1987,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) | |||
2280 | vout->vid_info.num_overlays = 1; | 1987 | vout->vid_info.num_overlays = 1; |
2281 | vout->vid_info.id = k + 1; | 1988 | vout->vid_info.id = k + 1; |
2282 | 1989 | ||
1990 | /* Set VRFB as rotation_type for omap2 and omap3 */ | ||
1991 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
1992 | vout->vid_info.rotation_type = VOUT_ROT_VRFB; | ||
1993 | |||
2283 | /* Setup the default configuration for the video devices | 1994 | /* Setup the default configuration for the video devices |
2284 | */ | 1995 | */ |
2285 | if (omap_vout_setup_video_data(vout) != 0) { | 1996 | if (omap_vout_setup_video_data(vout) != 0) { |
@@ -2313,7 +2024,8 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) | |||
2313 | goto success; | 2024 | goto success; |
2314 | 2025 | ||
2315 | error2: | 2026 | error2: |
2316 | omap_vout_release_vrfb(vout); | 2027 | if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) |
2028 | omap_vout_release_vrfb(vout); | ||
2317 | omap_vout_free_buffers(vout); | 2029 | omap_vout_free_buffers(vout); |
2318 | error1: | 2030 | error1: |
2319 | video_device_release(vfd); | 2031 | video_device_release(vfd); |
@@ -2334,11 +2046,13 @@ success: | |||
2334 | static void omap_vout_cleanup_device(struct omap_vout_device *vout) | 2046 | static void omap_vout_cleanup_device(struct omap_vout_device *vout) |
2335 | { | 2047 | { |
2336 | struct video_device *vfd; | 2048 | struct video_device *vfd; |
2049 | struct omapvideo_info *ovid; | ||
2337 | 2050 | ||
2338 | if (!vout) | 2051 | if (!vout) |
2339 | return; | 2052 | return; |
2340 | 2053 | ||
2341 | vfd = vout->vfd; | 2054 | vfd = vout->vfd; |
2055 | ovid = &vout->vid_info; | ||
2342 | if (vfd) { | 2056 | if (vfd) { |
2343 | if (!video_is_registered(vfd)) { | 2057 | if (!video_is_registered(vfd)) { |
2344 | /* | 2058 | /* |
@@ -2354,14 +2068,15 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout) | |||
2354 | video_unregister_device(vfd); | 2068 | video_unregister_device(vfd); |
2355 | } | 2069 | } |
2356 | } | 2070 | } |
2357 | 2071 | if (ovid->rotation_type == VOUT_ROT_VRFB) { | |
2358 | omap_vout_release_vrfb(vout); | 2072 | omap_vout_release_vrfb(vout); |
2073 | /* Free the VRFB buffer if allocated | ||
2074 | * init time | ||
2075 | */ | ||
2076 | if (vout->vrfb_static_allocation) | ||
2077 | omap_vout_free_vrfb_buffers(vout); | ||
2078 | } | ||
2359 | omap_vout_free_buffers(vout); | 2079 | omap_vout_free_buffers(vout); |
2360 | /* Free the VRFB buffer if allocated | ||
2361 | * init time | ||
2362 | */ | ||
2363 | if (vout->vrfb_static_allocation) | ||
2364 | omap_vout_free_vrfb_buffers(vout); | ||
2365 | 2080 | ||
2366 | kfree(vout); | 2081 | kfree(vout); |
2367 | } | 2082 | } |
diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/video/omap/omap_vout_vrfb.c new file mode 100644 index 000000000000..ebebcac49225 --- /dev/null +++ b/drivers/media/video/omap/omap_vout_vrfb.c | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * omap_vout_vrfb.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments. | ||
5 | * | ||
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. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/videodev2.h> | ||
15 | |||
16 | #include <media/videobuf-dma-contig.h> | ||
17 | #include <media/v4l2-device.h> | ||
18 | |||
19 | #include <plat/dma.h> | ||
20 | #include <plat/vrfb.h> | ||
21 | |||
22 | #include "omap_voutdef.h" | ||
23 | #include "omap_voutlib.h" | ||
24 | |||
25 | /* | ||
26 | * Function for allocating video buffers | ||
27 | */ | ||
28 | static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, | ||
29 | unsigned int *count, int startindex) | ||
30 | { | ||
31 | int i, j; | ||
32 | |||
33 | for (i = 0; i < *count; i++) { | ||
34 | if (!vout->smsshado_virt_addr[i]) { | ||
35 | vout->smsshado_virt_addr[i] = | ||
36 | omap_vout_alloc_buffer(vout->smsshado_size, | ||
37 | &vout->smsshado_phy_addr[i]); | ||
38 | } | ||
39 | if (!vout->smsshado_virt_addr[i] && startindex != -1) { | ||
40 | if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex) | ||
41 | break; | ||
42 | } | ||
43 | if (!vout->smsshado_virt_addr[i]) { | ||
44 | for (j = 0; j < i; j++) { | ||
45 | omap_vout_free_buffer( | ||
46 | vout->smsshado_virt_addr[j], | ||
47 | vout->smsshado_size); | ||
48 | vout->smsshado_virt_addr[j] = 0; | ||
49 | vout->smsshado_phy_addr[j] = 0; | ||
50 | } | ||
51 | *count = 0; | ||
52 | return -ENOMEM; | ||
53 | } | ||
54 | memset((void *) vout->smsshado_virt_addr[i], 0, | ||
55 | vout->smsshado_size); | ||
56 | } | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Wakes up the application once the DMA transfer to VRFB space is completed. | ||
62 | */ | ||
63 | static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data) | ||
64 | { | ||
65 | struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data; | ||
66 | |||
67 | t->tx_status = 1; | ||
68 | wake_up_interruptible(&t->wait); | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Free VRFB buffers | ||
73 | */ | ||
74 | void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) | ||
75 | { | ||
76 | int j; | ||
77 | |||
78 | for (j = 0; j < VRFB_NUM_BUFS; j++) { | ||
79 | omap_vout_free_buffer(vout->smsshado_virt_addr[j], | ||
80 | vout->smsshado_size); | ||
81 | vout->smsshado_virt_addr[j] = 0; | ||
82 | vout->smsshado_phy_addr[j] = 0; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, | ||
87 | u32 static_vrfb_allocation) | ||
88 | { | ||
89 | int ret = 0, i, j; | ||
90 | struct omap_vout_device *vout; | ||
91 | struct video_device *vfd; | ||
92 | int image_width, image_height; | ||
93 | int vrfb_num_bufs = VRFB_NUM_BUFS; | ||
94 | struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); | ||
95 | struct omap2video_device *vid_dev = | ||
96 | container_of(v4l2_dev, struct omap2video_device, v4l2_dev); | ||
97 | |||
98 | vout = vid_dev->vouts[vid_num]; | ||
99 | vfd = vout->vfd; | ||
100 | |||
101 | for (i = 0; i < VRFB_NUM_BUFS; i++) { | ||
102 | if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { | ||
103 | dev_info(&pdev->dev, ": VRFB allocation failed\n"); | ||
104 | for (j = 0; j < i; j++) | ||
105 | omap_vrfb_release_ctx(&vout->vrfb_context[j]); | ||
106 | ret = -ENOMEM; | ||
107 | goto free_buffers; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* Calculate VRFB memory size */ | ||
112 | /* allocate for worst case size */ | ||
113 | image_width = VID_MAX_WIDTH / TILE_SIZE; | ||
114 | if (VID_MAX_WIDTH % TILE_SIZE) | ||
115 | image_width++; | ||
116 | |||
117 | image_width = image_width * TILE_SIZE; | ||
118 | image_height = VID_MAX_HEIGHT / TILE_SIZE; | ||
119 | |||
120 | if (VID_MAX_HEIGHT % TILE_SIZE) | ||
121 | image_height++; | ||
122 | |||
123 | image_height = image_height * TILE_SIZE; | ||
124 | vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); | ||
125 | |||
126 | /* | ||
127 | * Request and Initialize DMA, for DMA based VRFB transfer | ||
128 | */ | ||
129 | vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; | ||
130 | vout->vrfb_dma_tx.dma_ch = -1; | ||
131 | vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; | ||
132 | ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", | ||
133 | omap_vout_vrfb_dma_tx_callback, | ||
134 | (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); | ||
135 | if (ret < 0) { | ||
136 | vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; | ||
137 | dev_info(&pdev->dev, ": failed to allocate DMA Channel for" | ||
138 | " video%d\n", vfd->minor); | ||
139 | } | ||
140 | init_waitqueue_head(&vout->vrfb_dma_tx.wait); | ||
141 | |||
142 | /* statically allocated the VRFB buffer is done through | ||
143 | commands line aruments */ | ||
144 | if (static_vrfb_allocation) { | ||
145 | if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { | ||
146 | ret = -ENOMEM; | ||
147 | goto release_vrfb_ctx; | ||
148 | } | ||
149 | vout->vrfb_static_allocation = 1; | ||
150 | } | ||
151 | return 0; | ||
152 | |||
153 | release_vrfb_ctx: | ||
154 | for (j = 0; j < VRFB_NUM_BUFS; j++) | ||
155 | omap_vrfb_release_ctx(&vout->vrfb_context[j]); | ||
156 | free_buffers: | ||
157 | omap_vout_free_buffers(vout); | ||
158 | |||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * Release the VRFB context once the module exits | ||
164 | */ | ||
165 | void omap_vout_release_vrfb(struct omap_vout_device *vout) | ||
166 | { | ||
167 | int i; | ||
168 | |||
169 | for (i = 0; i < VRFB_NUM_BUFS; i++) | ||
170 | omap_vrfb_release_ctx(&vout->vrfb_context[i]); | ||
171 | |||
172 | if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) { | ||
173 | vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; | ||
174 | omap_free_dma(vout->vrfb_dma_tx.dma_ch); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Allocate the buffers for the VRFB space. Data is copied from V4L2 | ||
180 | * buffers to the VRFB buffers using the DMA engine. | ||
181 | */ | ||
182 | int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, | ||
183 | unsigned int *count, unsigned int startindex) | ||
184 | { | ||
185 | int i; | ||
186 | bool yuv_mode; | ||
187 | |||
188 | if (!is_rotation_enabled(vout)) | ||
189 | return 0; | ||
190 | |||
191 | /* If rotation is enabled, allocate memory for VRFB space also */ | ||
192 | *count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count; | ||
193 | |||
194 | /* Allocate the VRFB buffers only if the buffers are not | ||
195 | * allocated during init time. | ||
196 | */ | ||
197 | if (!vout->vrfb_static_allocation) | ||
198 | if (omap_vout_allocate_vrfb_buffers(vout, count, startindex)) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 || | ||
202 | vout->dss_mode == OMAP_DSS_COLOR_UYVY) | ||
203 | yuv_mode = true; | ||
204 | else | ||
205 | yuv_mode = false; | ||
206 | |||
207 | for (i = 0; i < *count; i++) | ||
208 | omap_vrfb_setup(&vout->vrfb_context[i], | ||
209 | vout->smsshado_phy_addr[i], vout->pix.width, | ||
210 | vout->pix.height, vout->bpp, yuv_mode); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | int omap_vout_prepare_vrfb(struct omap_vout_device *vout, | ||
216 | struct videobuf_buffer *vb) | ||
217 | { | ||
218 | dma_addr_t dmabuf; | ||
219 | struct vid_vrfb_dma *tx; | ||
220 | enum dss_rotation rotation; | ||
221 | u32 dest_frame_index = 0, src_element_index = 0; | ||
222 | u32 dest_element_index = 0, src_frame_index = 0; | ||
223 | u32 elem_count = 0, frame_count = 0, pixsize = 2; | ||
224 | |||
225 | if (!is_rotation_enabled(vout)) | ||
226 | return 0; | ||
227 | |||
228 | dmabuf = vout->buf_phy_addr[vb->i]; | ||
229 | /* If rotation is enabled, copy input buffer into VRFB | ||
230 | * memory space using DMA. We are copying input buffer | ||
231 | * into VRFB memory space of desired angle and DSS will | ||
232 | * read image VRFB memory for 0 degree angle | ||
233 | */ | ||
234 | pixsize = vout->bpp * vout->vrfb_bpp; | ||
235 | /* | ||
236 | * DMA transfer in double index mode | ||
237 | */ | ||
238 | |||
239 | /* Frame index */ | ||
240 | dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) - | ||
241 | (vout->pix.width * vout->bpp)) + 1; | ||
242 | |||
243 | /* Source and destination parameters */ | ||
244 | src_element_index = 0; | ||
245 | src_frame_index = 0; | ||
246 | dest_element_index = 1; | ||
247 | /* Number of elements per frame */ | ||
248 | elem_count = vout->pix.width * vout->bpp; | ||
249 | frame_count = vout->pix.height; | ||
250 | tx = &vout->vrfb_dma_tx; | ||
251 | tx->tx_status = 0; | ||
252 | omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32, | ||
253 | (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT, | ||
254 | tx->dev_id, 0x0); | ||
255 | /* src_port required only for OMAP1 */ | ||
256 | omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, | ||
257 | dmabuf, src_element_index, src_frame_index); | ||
258 | /*set dma source burst mode for VRFB */ | ||
259 | omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
260 | rotation = calc_rotation(vout); | ||
261 | |||
262 | /* dest_port required only for OMAP1 */ | ||
263 | omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX, | ||
264 | vout->vrfb_context[vb->i].paddr[0], dest_element_index, | ||
265 | dest_frame_index); | ||
266 | /*set dma dest burst mode for VRFB */ | ||
267 | omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
268 | omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0); | ||
269 | |||
270 | omap_start_dma(tx->dma_ch); | ||
271 | interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT); | ||
272 | |||
273 | if (tx->tx_status == 0) { | ||
274 | omap_stop_dma(tx->dma_ch); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | /* Store buffers physical address into an array. Addresses | ||
278 | * from this array will be used to configure DSS */ | ||
279 | vout->queued_buf_addr[vb->i] = (u8 *) | ||
280 | vout->vrfb_context[vb->i].paddr[rotation]; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Calculate the buffer offsets from which the streaming should | ||
286 | * start. This offset calculation is mainly required because of | ||
287 | * the VRFB 32 pixels alignment with rotation. | ||
288 | */ | ||
289 | void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) | ||
290 | { | ||
291 | enum dss_rotation rotation; | ||
292 | bool mirroring = vout->mirror; | ||
293 | struct v4l2_rect *crop = &vout->crop; | ||
294 | struct v4l2_pix_format *pix = &vout->pix; | ||
295 | int *cropped_offset = &vout->cropped_offset; | ||
296 | int vr_ps = 1, ps = 2, temp_ps = 2; | ||
297 | int offset = 0, ctop = 0, cleft = 0, line_length = 0; | ||
298 | |||
299 | rotation = calc_rotation(vout); | ||
300 | |||
301 | if (V4L2_PIX_FMT_YUYV == pix->pixelformat || | ||
302 | V4L2_PIX_FMT_UYVY == pix->pixelformat) { | ||
303 | if (is_rotation_enabled(vout)) { | ||
304 | /* | ||
305 | * ps - Actual pixel size for YUYV/UYVY for | ||
306 | * VRFB/Mirroring is 4 bytes | ||
307 | * vr_ps - Virtually pixel size for YUYV/UYVY is | ||
308 | * 2 bytes | ||
309 | */ | ||
310 | ps = 4; | ||
311 | vr_ps = 2; | ||
312 | } else { | ||
313 | ps = 2; /* otherwise the pixel size is 2 byte */ | ||
314 | } | ||
315 | } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) { | ||
316 | ps = 4; | ||
317 | } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) { | ||
318 | ps = 3; | ||
319 | } | ||
320 | vout->ps = ps; | ||
321 | vout->vr_ps = vr_ps; | ||
322 | |||
323 | if (is_rotation_enabled(vout)) { | ||
324 | line_length = MAX_PIXELS_PER_LINE; | ||
325 | ctop = (pix->height - crop->height) - crop->top; | ||
326 | cleft = (pix->width - crop->width) - crop->left; | ||
327 | } else { | ||
328 | line_length = pix->width; | ||
329 | } | ||
330 | vout->line_length = line_length; | ||
331 | switch (rotation) { | ||
332 | case dss_rotation_90_degree: | ||
333 | offset = vout->vrfb_context[0].yoffset * | ||
334 | vout->vrfb_context[0].bytespp; | ||
335 | temp_ps = ps / vr_ps; | ||
336 | if (mirroring == 0) { | ||
337 | *cropped_offset = offset + line_length * | ||
338 | temp_ps * cleft + crop->top * temp_ps; | ||
339 | } else { | ||
340 | *cropped_offset = offset + line_length * temp_ps * | ||
341 | cleft + crop->top * temp_ps + (line_length * | ||
342 | ((crop->width / (vr_ps)) - 1) * ps); | ||
343 | } | ||
344 | break; | ||
345 | case dss_rotation_180_degree: | ||
346 | offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset * | ||
347 | vout->vrfb_context[0].bytespp) + | ||
348 | (vout->vrfb_context[0].xoffset * | ||
349 | vout->vrfb_context[0].bytespp)); | ||
350 | if (mirroring == 0) { | ||
351 | *cropped_offset = offset + (line_length * ps * ctop) + | ||
352 | (cleft / vr_ps) * ps; | ||
353 | |||
354 | } else { | ||
355 | *cropped_offset = offset + (line_length * ps * ctop) + | ||
356 | (cleft / vr_ps) * ps + (line_length * | ||
357 | (crop->height - 1) * ps); | ||
358 | } | ||
359 | break; | ||
360 | case dss_rotation_270_degree: | ||
361 | offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset * | ||
362 | vout->vrfb_context[0].bytespp; | ||
363 | temp_ps = ps / vr_ps; | ||
364 | if (mirroring == 0) { | ||
365 | *cropped_offset = offset + line_length * | ||
366 | temp_ps * crop->left + ctop * ps; | ||
367 | } else { | ||
368 | *cropped_offset = offset + line_length * | ||
369 | temp_ps * crop->left + ctop * ps + | ||
370 | (line_length * ((crop->width / vr_ps) - 1) * | ||
371 | ps); | ||
372 | } | ||
373 | break; | ||
374 | case dss_rotation_0_degree: | ||
375 | if (mirroring == 0) { | ||
376 | *cropped_offset = (line_length * ps) * | ||
377 | crop->top + (crop->left / vr_ps) * ps; | ||
378 | } else { | ||
379 | *cropped_offset = (line_length * ps) * | ||
380 | crop->top + (crop->left / vr_ps) * ps + | ||
381 | (line_length * (crop->height - 1) * ps); | ||
382 | } | ||
383 | break; | ||
384 | default: | ||
385 | *cropped_offset = (line_length * ps * crop->top) / | ||
386 | vr_ps + (crop->left * ps) / vr_ps + | ||
387 | ((crop->width / vr_ps) - 1) * ps; | ||
388 | break; | ||
389 | } | ||
390 | } | ||
diff --git a/drivers/media/video/omap/omap_vout_vrfb.h b/drivers/media/video/omap/omap_vout_vrfb.h new file mode 100644 index 000000000000..ffde741e0590 --- /dev/null +++ b/drivers/media/video/omap/omap_vout_vrfb.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * omap_vout_vrfb.h | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments. | ||
5 | * | ||
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. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef OMAP_VOUT_VRFB_H | ||
13 | #define OMAP_VOUT_VRFB_H | ||
14 | |||
15 | #ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB | ||
16 | void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout); | ||
17 | int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, | ||
18 | u32 static_vrfb_allocation); | ||
19 | void omap_vout_release_vrfb(struct omap_vout_device *vout); | ||
20 | int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, | ||
21 | unsigned int *count, unsigned int startindex); | ||
22 | int omap_vout_prepare_vrfb(struct omap_vout_device *vout, | ||
23 | struct videobuf_buffer *vb); | ||
24 | void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout); | ||
25 | #else | ||
26 | void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { } | ||
27 | int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, | ||
28 | u32 static_vrfb_allocation) | ||
29 | { return 0; } | ||
30 | void omap_vout_release_vrfb(struct omap_vout_device *vout) { } | ||
31 | int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, | ||
32 | unsigned int *count, unsigned int startindex) | ||
33 | { return 0; } | ||
34 | int omap_vout_prepare_vrfb(struct omap_vout_device *vout, | ||
35 | struct videobuf_buffer *vb) | ||
36 | { return 0; } | ||
37 | void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { } | ||
38 | #endif | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h index 1ef3ed22660c..d793501cafcc 100644 --- a/drivers/media/video/omap/omap_voutdef.h +++ b/drivers/media/video/omap/omap_voutdef.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #define OMAP_VOUTDEF_H | 12 | #define OMAP_VOUTDEF_H |
13 | 13 | ||
14 | #include <video/omapdss.h> | 14 | #include <video/omapdss.h> |
15 | #include <plat/vrfb.h> | ||
15 | 16 | ||
16 | #define YUYV_BPP 2 | 17 | #define YUYV_BPP 2 |
17 | #define RGB565_BPP 2 | 18 | #define RGB565_BPP 2 |
@@ -62,6 +63,18 @@ enum dss_rotation { | |||
62 | dss_rotation_180_degree = 2, | 63 | dss_rotation_180_degree = 2, |
63 | dss_rotation_270_degree = 3, | 64 | dss_rotation_270_degree = 3, |
64 | }; | 65 | }; |
66 | |||
67 | /* Enum for choosing rotation type for vout | ||
68 | * DSS2 doesn't understand no rotation as an | ||
69 | * option while V4L2 driver doesn't support | ||
70 | * rotation in the case where VRFB is not built in | ||
71 | * the kernel | ||
72 | */ | ||
73 | enum vout_rotaion_type { | ||
74 | VOUT_ROT_NONE = 0, | ||
75 | VOUT_ROT_VRFB = 1, | ||
76 | }; | ||
77 | |||
65 | /* | 78 | /* |
66 | * This structure is used to store the DMA transfer parameters | 79 | * This structure is used to store the DMA transfer parameters |
67 | * for VRFB hidden buffer | 80 | * for VRFB hidden buffer |
@@ -78,6 +91,7 @@ struct omapvideo_info { | |||
78 | int id; | 91 | int id; |
79 | int num_overlays; | 92 | int num_overlays; |
80 | struct omap_overlay *overlays[MAX_OVLS]; | 93 | struct omap_overlay *overlays[MAX_OVLS]; |
94 | enum vout_rotaion_type rotation_type; | ||
81 | }; | 95 | }; |
82 | 96 | ||
83 | struct omap2video_device { | 97 | struct omap2video_device { |
@@ -206,4 +220,6 @@ static inline int calc_rotation(const struct omap_vout_device *vout) | |||
206 | return dss_rotation_180_degree; | 220 | return dss_rotation_180_degree; |
207 | } | 221 | } |
208 | } | 222 | } |
223 | |||
224 | void omap_vout_free_buffers(struct omap_vout_device *vout); | ||
209 | #endif /* ifndef OMAP_VOUTDEF_H */ | 225 | #endif /* ifndef OMAP_VOUTDEF_H */ |