Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: "The first part of the media updates for Kernel 3.7. This series contain: - A major tree renaming patch series: now, drivers are organized internally by their used bus, instead of by V4L2 and/or DVB API, providing a cleaner driver location for hybrid drivers that implement both APIs, and allowing to cleanup the Kconfig items and make them more intuitive for the end user; - Media Kernel developers are typically very lazy with their duties of keeping the MAINTAINERS entries for their drivers updated. As now the tree is more organized, we're doing an effort to add/update those entries for the drivers that aren't currently orphan; - Several DVB USB drivers got moved to a new DVB USB v2 core; the new core fixes several bugs (as the existing one that got bitroted). Now, suspend/resume finally started to work fine (at least with some devices - we should expect more work with regards to it); - added multistream support for DVB-T2, and unified the API for DVB-S2 and ISDB-S. Backward binary support is preserved; - as usual, a few new drivers, some V4L2 core improvements and lots of drivers improvements and fixes. There are some points to notice on this series: 1) you should expect a trivial merge conflict on your tree, with the removal of Documentation/feature-removal-schedule.txt: this series would be adding two additional entries there. I opted to not rebase it due to this recent change; 2) With regards to the PCTV 520e udev-related breakage, I opted to fix it in a way that the patches can be backported to 3.5 even without your firmware fix patch. This way, Greg doesn't need to rush backporting your patch (as there are still the firmware cache and firmware path customization issues to be addressed there). I'll send later a patch (likely after the end of the merge window) reverting the rest of the DRX-K async firmware request, fully restoring its original behaviour to allow media drivers to initialize everything serialized as before for 3.7 and upper. 3) I'm planning to work on this weekend to test the DMABUF patches for V4L2. The patches are on my queue for several Kernel cycles, but, up to now, there is/was no way to test the series locally. I have some concerns about this particular changeset with regards to security issues, and with regards to the replacement of the old VIDIOC_OVERLAY ioctl's that is broken on modern systems, due to GPU drivers change. The Overlay API allows direct PCI2PCI transfers from a media capture card into the GPU framebuffer, but its API is crappy. Also, the only existing X11 driver that implements it requires a XV extension that is not available anymore on modern drivers. The DMABUF can do the same thing, but with it is promising to be a properly-designed API. If I can successfully test this series and be happy with it, I should be asking you to pull them next week." * 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (717 commits) em28xx: regression fix: use DRX-K sync firmware requests on em28xx drxk: allow loading firmware synchrousnously em28xx: Make all em28xx extensions to be initialized asynchronously [media] tda18271: properly report read errors in tda18271_get_id [media] tda18271: delay IR & RF calibration until init() if delay_cal is set [media] MAINTAINERS: add Michael Krufky as tda827x maintainer [media] MAINTAINERS: add Michael Krufky as tda8290 maintainer [media] MAINTAINERS: add Michael Krufky as cxusb maintainer [media] MAINTAINERS: add Michael Krufky as lg2160 maintainer [media] MAINTAINERS: add Michael Krufky as lgdt3305 maintainer [media] MAINTAINERS: add Michael Krufky as mxl111sf maintainer [media] MAINTAINERS: add Michael Krufky as mxl5007t maintainer [media] MAINTAINERS: add Michael Krufky as tda18271 maintainer [media] s5p-tv: Report only multi-plane capabilities in vidioc_querycap [media] s5p-mfc: Fix misplaced return statement in s5p_mfc_suspend() [media] exynos-gsc: Add missing static storage class specifiers [media] exynos-gsc: Remove <linux/version.h> header file inclusion [media] s5p-fimc: Fix incorrect condition in fimc_lite_reqbufs() [media] s5p-tv: Fix potential NULL pointer dereference error [media] s5k6aa: Fix possible NULL pointer dereference ...
This commit is contained in:
14
drivers/media/platform/omap/Kconfig
Normal file
14
drivers/media/platform/omap/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
config VIDEO_OMAP2_VOUT_VRFB
|
||||
bool
|
||||
|
||||
config VIDEO_OMAP2_VOUT
|
||||
tristate "OMAP2/OMAP3 V4L2-Display driver"
|
||||
depends on ARCH_OMAP2 || ARCH_OMAP3
|
||||
select VIDEOBUF_GEN
|
||||
select VIDEOBUF_DMA_CONTIG
|
||||
select OMAP2_DSS
|
||||
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
|
||||
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
|
||||
default n
|
||||
---help---
|
||||
V4L2 Display driver support for OMAP2/3 based boards.
|
8
drivers/media/platform/omap/Makefile
Normal file
8
drivers/media/platform/omap/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Makefile for the omap video device drivers.
|
||||
#
|
||||
|
||||
# OMAP2/3 Display driver
|
||||
omap-vout-y += omap_vout.o omap_voutlib.o
|
||||
omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
|
||||
obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
|
2291
drivers/media/platform/omap/omap_vout.c
Normal file
2291
drivers/media/platform/omap/omap_vout.c
Normal file
File diff suppressed because it is too large
Load Diff
390
drivers/media/platform/omap/omap_vout_vrfb.c
Normal file
390
drivers/media/platform/omap/omap_vout_vrfb.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* omap_vout_vrfb.c
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
#include <plat/vrfb.h>
|
||||
|
||||
#include "omap_voutdef.h"
|
||||
#include "omap_voutlib.h"
|
||||
|
||||
/*
|
||||
* Function for allocating video buffers
|
||||
*/
|
||||
static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
|
||||
unsigned int *count, int startindex)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
if (!vout->smsshado_virt_addr[i]) {
|
||||
vout->smsshado_virt_addr[i] =
|
||||
omap_vout_alloc_buffer(vout->smsshado_size,
|
||||
&vout->smsshado_phy_addr[i]);
|
||||
}
|
||||
if (!vout->smsshado_virt_addr[i] && startindex != -1) {
|
||||
if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
|
||||
break;
|
||||
}
|
||||
if (!vout->smsshado_virt_addr[i]) {
|
||||
for (j = 0; j < i; j++) {
|
||||
omap_vout_free_buffer(
|
||||
vout->smsshado_virt_addr[j],
|
||||
vout->smsshado_size);
|
||||
vout->smsshado_virt_addr[j] = 0;
|
||||
vout->smsshado_phy_addr[j] = 0;
|
||||
}
|
||||
*count = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void *) vout->smsshado_virt_addr[i], 0,
|
||||
vout->smsshado_size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wakes up the application once the DMA transfer to VRFB space is completed.
|
||||
*/
|
||||
static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
|
||||
{
|
||||
struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
|
||||
|
||||
t->tx_status = 1;
|
||||
wake_up_interruptible(&t->wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free VRFB buffers
|
||||
*/
|
||||
void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < VRFB_NUM_BUFS; j++) {
|
||||
omap_vout_free_buffer(vout->smsshado_virt_addr[j],
|
||||
vout->smsshado_size);
|
||||
vout->smsshado_virt_addr[j] = 0;
|
||||
vout->smsshado_phy_addr[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
|
||||
bool static_vrfb_allocation)
|
||||
{
|
||||
int ret = 0, i, j;
|
||||
struct omap_vout_device *vout;
|
||||
struct video_device *vfd;
|
||||
int image_width, image_height;
|
||||
int vrfb_num_bufs = VRFB_NUM_BUFS;
|
||||
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
|
||||
struct omap2video_device *vid_dev =
|
||||
container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
|
||||
|
||||
vout = vid_dev->vouts[vid_num];
|
||||
vfd = vout->vfd;
|
||||
|
||||
for (i = 0; i < VRFB_NUM_BUFS; i++) {
|
||||
if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
|
||||
dev_info(&pdev->dev, ": VRFB allocation failed\n");
|
||||
for (j = 0; j < i; j++)
|
||||
omap_vrfb_release_ctx(&vout->vrfb_context[j]);
|
||||
ret = -ENOMEM;
|
||||
goto free_buffers;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate VRFB memory size */
|
||||
/* allocate for worst case size */
|
||||
image_width = VID_MAX_WIDTH / TILE_SIZE;
|
||||
if (VID_MAX_WIDTH % TILE_SIZE)
|
||||
image_width++;
|
||||
|
||||
image_width = image_width * TILE_SIZE;
|
||||
image_height = VID_MAX_HEIGHT / TILE_SIZE;
|
||||
|
||||
if (VID_MAX_HEIGHT % TILE_SIZE)
|
||||
image_height++;
|
||||
|
||||
image_height = image_height * TILE_SIZE;
|
||||
vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
|
||||
|
||||
/*
|
||||
* Request and Initialize DMA, for DMA based VRFB transfer
|
||||
*/
|
||||
vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
|
||||
vout->vrfb_dma_tx.dma_ch = -1;
|
||||
vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
|
||||
ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
|
||||
omap_vout_vrfb_dma_tx_callback,
|
||||
(void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
|
||||
if (ret < 0) {
|
||||
vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
|
||||
dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
|
||||
" video%d\n", vfd->minor);
|
||||
}
|
||||
init_waitqueue_head(&vout->vrfb_dma_tx.wait);
|
||||
|
||||
/* statically allocated the VRFB buffer is done through
|
||||
commands line aruments */
|
||||
if (static_vrfb_allocation) {
|
||||
if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
|
||||
ret = -ENOMEM;
|
||||
goto release_vrfb_ctx;
|
||||
}
|
||||
vout->vrfb_static_allocation = 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
release_vrfb_ctx:
|
||||
for (j = 0; j < VRFB_NUM_BUFS; j++)
|
||||
omap_vrfb_release_ctx(&vout->vrfb_context[j]);
|
||||
free_buffers:
|
||||
omap_vout_free_buffers(vout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the VRFB context once the module exits
|
||||
*/
|
||||
void omap_vout_release_vrfb(struct omap_vout_device *vout)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VRFB_NUM_BUFS; i++)
|
||||
omap_vrfb_release_ctx(&vout->vrfb_context[i]);
|
||||
|
||||
if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
|
||||
vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
|
||||
omap_free_dma(vout->vrfb_dma_tx.dma_ch);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the buffers for the VRFB space. Data is copied from V4L2
|
||||
* buffers to the VRFB buffers using the DMA engine.
|
||||
*/
|
||||
int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
|
||||
unsigned int *count, unsigned int startindex)
|
||||
{
|
||||
int i;
|
||||
bool yuv_mode;
|
||||
|
||||
if (!is_rotation_enabled(vout))
|
||||
return 0;
|
||||
|
||||
/* If rotation is enabled, allocate memory for VRFB space also */
|
||||
*count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count;
|
||||
|
||||
/* Allocate the VRFB buffers only if the buffers are not
|
||||
* allocated during init time.
|
||||
*/
|
||||
if (!vout->vrfb_static_allocation)
|
||||
if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
|
||||
return -ENOMEM;
|
||||
|
||||
if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
|
||||
vout->dss_mode == OMAP_DSS_COLOR_UYVY)
|
||||
yuv_mode = true;
|
||||
else
|
||||
yuv_mode = false;
|
||||
|
||||
for (i = 0; i < *count; i++)
|
||||
omap_vrfb_setup(&vout->vrfb_context[i],
|
||||
vout->smsshado_phy_addr[i], vout->pix.width,
|
||||
vout->pix.height, vout->bpp, yuv_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
|
||||
struct videobuf_buffer *vb)
|
||||
{
|
||||
dma_addr_t dmabuf;
|
||||
struct vid_vrfb_dma *tx;
|
||||
enum dss_rotation rotation;
|
||||
u32 dest_frame_index = 0, src_element_index = 0;
|
||||
u32 dest_element_index = 0, src_frame_index = 0;
|
||||
u32 elem_count = 0, frame_count = 0, pixsize = 2;
|
||||
|
||||
if (!is_rotation_enabled(vout))
|
||||
return 0;
|
||||
|
||||
dmabuf = vout->buf_phy_addr[vb->i];
|
||||
/* If rotation is enabled, copy input buffer into VRFB
|
||||
* memory space using DMA. We are copying input buffer
|
||||
* into VRFB memory space of desired angle and DSS will
|
||||
* read image VRFB memory for 0 degree angle
|
||||
*/
|
||||
pixsize = vout->bpp * vout->vrfb_bpp;
|
||||
/*
|
||||
* DMA transfer in double index mode
|
||||
*/
|
||||
|
||||
/* Frame index */
|
||||
dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
|
||||
(vout->pix.width * vout->bpp)) + 1;
|
||||
|
||||
/* Source and destination parameters */
|
||||
src_element_index = 0;
|
||||
src_frame_index = 0;
|
||||
dest_element_index = 1;
|
||||
/* Number of elements per frame */
|
||||
elem_count = vout->pix.width * vout->bpp;
|
||||
frame_count = vout->pix.height;
|
||||
tx = &vout->vrfb_dma_tx;
|
||||
tx->tx_status = 0;
|
||||
omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
|
||||
(elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
|
||||
tx->dev_id, 0x0);
|
||||
/* src_port required only for OMAP1 */
|
||||
omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
|
||||
dmabuf, src_element_index, src_frame_index);
|
||||
/*set dma source burst mode for VRFB */
|
||||
omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
|
||||
rotation = calc_rotation(vout);
|
||||
|
||||
/* dest_port required only for OMAP1 */
|
||||
omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
|
||||
vout->vrfb_context[vb->i].paddr[0], dest_element_index,
|
||||
dest_frame_index);
|
||||
/*set dma dest burst mode for VRFB */
|
||||
omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
|
||||
omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
|
||||
|
||||
omap_start_dma(tx->dma_ch);
|
||||
interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
|
||||
|
||||
if (tx->tx_status == 0) {
|
||||
omap_stop_dma(tx->dma_ch);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Store buffers physical address into an array. Addresses
|
||||
* from this array will be used to configure DSS */
|
||||
vout->queued_buf_addr[vb->i] = (u8 *)
|
||||
vout->vrfb_context[vb->i].paddr[rotation];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the buffer offsets from which the streaming should
|
||||
* start. This offset calculation is mainly required because of
|
||||
* the VRFB 32 pixels alignment with rotation.
|
||||
*/
|
||||
void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
|
||||
{
|
||||
enum dss_rotation rotation;
|
||||
bool mirroring = vout->mirror;
|
||||
struct v4l2_rect *crop = &vout->crop;
|
||||
struct v4l2_pix_format *pix = &vout->pix;
|
||||
int *cropped_offset = &vout->cropped_offset;
|
||||
int vr_ps = 1, ps = 2, temp_ps = 2;
|
||||
int offset = 0, ctop = 0, cleft = 0, line_length = 0;
|
||||
|
||||
rotation = calc_rotation(vout);
|
||||
|
||||
if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
|
||||
V4L2_PIX_FMT_UYVY == pix->pixelformat) {
|
||||
if (is_rotation_enabled(vout)) {
|
||||
/*
|
||||
* ps - Actual pixel size for YUYV/UYVY for
|
||||
* VRFB/Mirroring is 4 bytes
|
||||
* vr_ps - Virtually pixel size for YUYV/UYVY is
|
||||
* 2 bytes
|
||||
*/
|
||||
ps = 4;
|
||||
vr_ps = 2;
|
||||
} else {
|
||||
ps = 2; /* otherwise the pixel size is 2 byte */
|
||||
}
|
||||
} else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
|
||||
ps = 4;
|
||||
} else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
|
||||
ps = 3;
|
||||
}
|
||||
vout->ps = ps;
|
||||
vout->vr_ps = vr_ps;
|
||||
|
||||
if (is_rotation_enabled(vout)) {
|
||||
line_length = MAX_PIXELS_PER_LINE;
|
||||
ctop = (pix->height - crop->height) - crop->top;
|
||||
cleft = (pix->width - crop->width) - crop->left;
|
||||
} else {
|
||||
line_length = pix->width;
|
||||
}
|
||||
vout->line_length = line_length;
|
||||
switch (rotation) {
|
||||
case dss_rotation_90_degree:
|
||||
offset = vout->vrfb_context[0].yoffset *
|
||||
vout->vrfb_context[0].bytespp;
|
||||
temp_ps = ps / vr_ps;
|
||||
if (mirroring == 0) {
|
||||
*cropped_offset = offset + line_length *
|
||||
temp_ps * cleft + crop->top * temp_ps;
|
||||
} else {
|
||||
*cropped_offset = offset + line_length * temp_ps *
|
||||
cleft + crop->top * temp_ps + (line_length *
|
||||
((crop->width / (vr_ps)) - 1) * ps);
|
||||
}
|
||||
break;
|
||||
case dss_rotation_180_degree:
|
||||
offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
|
||||
vout->vrfb_context[0].bytespp) +
|
||||
(vout->vrfb_context[0].xoffset *
|
||||
vout->vrfb_context[0].bytespp));
|
||||
if (mirroring == 0) {
|
||||
*cropped_offset = offset + (line_length * ps * ctop) +
|
||||
(cleft / vr_ps) * ps;
|
||||
|
||||
} else {
|
||||
*cropped_offset = offset + (line_length * ps * ctop) +
|
||||
(cleft / vr_ps) * ps + (line_length *
|
||||
(crop->height - 1) * ps);
|
||||
}
|
||||
break;
|
||||
case dss_rotation_270_degree:
|
||||
offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
|
||||
vout->vrfb_context[0].bytespp;
|
||||
temp_ps = ps / vr_ps;
|
||||
if (mirroring == 0) {
|
||||
*cropped_offset = offset + line_length *
|
||||
temp_ps * crop->left + ctop * ps;
|
||||
} else {
|
||||
*cropped_offset = offset + line_length *
|
||||
temp_ps * crop->left + ctop * ps +
|
||||
(line_length * ((crop->width / vr_ps) - 1) *
|
||||
ps);
|
||||
}
|
||||
break;
|
||||
case dss_rotation_0_degree:
|
||||
if (mirroring == 0) {
|
||||
*cropped_offset = (line_length * ps) *
|
||||
crop->top + (crop->left / vr_ps) * ps;
|
||||
} else {
|
||||
*cropped_offset = (line_length * ps) *
|
||||
crop->top + (crop->left / vr_ps) * ps +
|
||||
(line_length * (crop->height - 1) * ps);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*cropped_offset = (line_length * ps * crop->top) /
|
||||
vr_ps + (crop->left * ps) / vr_ps +
|
||||
((crop->width / vr_ps) - 1) * ps;
|
||||
break;
|
||||
}
|
||||
}
|
40
drivers/media/platform/omap/omap_vout_vrfb.h
Normal file
40
drivers/media/platform/omap/omap_vout_vrfb.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* omap_vout_vrfb.h
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OMAP_VOUT_VRFB_H
|
||||
#define OMAP_VOUT_VRFB_H
|
||||
|
||||
#ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB
|
||||
void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout);
|
||||
int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
|
||||
u32 static_vrfb_allocation);
|
||||
void omap_vout_release_vrfb(struct omap_vout_device *vout);
|
||||
int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
|
||||
unsigned int *count, unsigned int startindex);
|
||||
int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
|
||||
struct videobuf_buffer *vb);
|
||||
void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
|
||||
#else
|
||||
void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
|
||||
int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
|
||||
u32 static_vrfb_allocation)
|
||||
{ return 0; }
|
||||
void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
|
||||
int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
|
||||
unsigned int *count, unsigned int startindex)
|
||||
{ return 0; }
|
||||
int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
|
||||
struct videobuf_buffer *vb)
|
||||
{ return 0; }
|
||||
void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
|
||||
#endif
|
||||
|
||||
#endif
|
225
drivers/media/platform/omap/omap_voutdef.h
Normal file
225
drivers/media/platform/omap/omap_voutdef.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* omap_voutdef.h
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#ifndef OMAP_VOUTDEF_H
|
||||
#define OMAP_VOUTDEF_H
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <plat/vrfb.h>
|
||||
|
||||
#define YUYV_BPP 2
|
||||
#define RGB565_BPP 2
|
||||
#define RGB24_BPP 3
|
||||
#define RGB32_BPP 4
|
||||
#define TILE_SIZE 32
|
||||
#define YUYV_VRFB_BPP 2
|
||||
#define RGB_VRFB_BPP 1
|
||||
#define MAX_CID 3
|
||||
#define MAC_VRFB_CTXS 4
|
||||
#define MAX_VOUT_DEV 2
|
||||
#define MAX_OVLS 3
|
||||
#define MAX_DISPLAYS 10
|
||||
#define MAX_MANAGERS 3
|
||||
|
||||
#define QQVGA_WIDTH 160
|
||||
#define QQVGA_HEIGHT 120
|
||||
|
||||
/* Max Resolution supported by the driver */
|
||||
#define VID_MAX_WIDTH 1280 /* Largest width */
|
||||
#define VID_MAX_HEIGHT 720 /* Largest height */
|
||||
|
||||
/* Mimimum requirement is 2x2 for DSS */
|
||||
#define VID_MIN_WIDTH 2
|
||||
#define VID_MIN_HEIGHT 2
|
||||
|
||||
/* 2048 x 2048 is max res supported by OMAP display controller */
|
||||
#define MAX_PIXELS_PER_LINE 2048
|
||||
|
||||
#define VRFB_TX_TIMEOUT 1000
|
||||
#define VRFB_NUM_BUFS 4
|
||||
|
||||
/* Max buffer size tobe allocated during init */
|
||||
#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
|
||||
|
||||
enum dma_channel_state {
|
||||
DMA_CHAN_NOT_ALLOTED,
|
||||
DMA_CHAN_ALLOTED,
|
||||
};
|
||||
|
||||
/* Enum for Rotation
|
||||
* DSS understands rotation in 0, 1, 2, 3 context
|
||||
* while V4L2 driver understands it as 0, 90, 180, 270
|
||||
*/
|
||||
enum dss_rotation {
|
||||
dss_rotation_0_degree = 0,
|
||||
dss_rotation_90_degree = 1,
|
||||
dss_rotation_180_degree = 2,
|
||||
dss_rotation_270_degree = 3,
|
||||
};
|
||||
|
||||
/* Enum for choosing rotation type for vout
|
||||
* DSS2 doesn't understand no rotation as an
|
||||
* option while V4L2 driver doesn't support
|
||||
* rotation in the case where VRFB is not built in
|
||||
* the kernel
|
||||
*/
|
||||
enum vout_rotaion_type {
|
||||
VOUT_ROT_NONE = 0,
|
||||
VOUT_ROT_VRFB = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is used to store the DMA transfer parameters
|
||||
* for VRFB hidden buffer
|
||||
*/
|
||||
struct vid_vrfb_dma {
|
||||
int dev_id;
|
||||
int dma_ch;
|
||||
int req_status;
|
||||
int tx_status;
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
struct omapvideo_info {
|
||||
int id;
|
||||
int num_overlays;
|
||||
struct omap_overlay *overlays[MAX_OVLS];
|
||||
enum vout_rotaion_type rotation_type;
|
||||
};
|
||||
|
||||
struct omap2video_device {
|
||||
struct mutex mtx;
|
||||
|
||||
int state;
|
||||
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct omap_vout_device *vouts[MAX_VOUT_DEV];
|
||||
|
||||
int num_displays;
|
||||
struct omap_dss_device *displays[MAX_DISPLAYS];
|
||||
int num_overlays;
|
||||
struct omap_overlay *overlays[MAX_OVLS];
|
||||
int num_managers;
|
||||
struct omap_overlay_manager *managers[MAX_MANAGERS];
|
||||
};
|
||||
|
||||
/* per-device data structure */
|
||||
struct omap_vout_device {
|
||||
|
||||
struct omapvideo_info vid_info;
|
||||
struct video_device *vfd;
|
||||
struct omap2video_device *vid_dev;
|
||||
int vid;
|
||||
int opened;
|
||||
|
||||
/* we don't allow to change image fmt/size once buffer has
|
||||
* been allocated
|
||||
*/
|
||||
int buffer_allocated;
|
||||
/* allow to reuse previously allocated buffer which is big enough */
|
||||
int buffer_size;
|
||||
/* keep buffer info across opens */
|
||||
unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
|
||||
unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
|
||||
enum omap_color_mode dss_mode;
|
||||
|
||||
/* we don't allow to request new buffer when old buffers are
|
||||
* still mmaped
|
||||
*/
|
||||
int mmap_count;
|
||||
|
||||
spinlock_t vbq_lock; /* spinlock for videobuf queues */
|
||||
unsigned long field_count; /* field counter for videobuf_buffer */
|
||||
|
||||
/* non-NULL means streaming is in progress. */
|
||||
bool streaming;
|
||||
|
||||
struct v4l2_pix_format pix;
|
||||
struct v4l2_rect crop;
|
||||
struct v4l2_window win;
|
||||
struct v4l2_framebuffer fbuf;
|
||||
|
||||
/* Lock to protect the shared data structures in ioctl */
|
||||
struct mutex lock;
|
||||
|
||||
/* V4L2 control structure for different control id */
|
||||
struct v4l2_control control[MAX_CID];
|
||||
enum dss_rotation rotation;
|
||||
bool mirror;
|
||||
int flicker_filter;
|
||||
/* V4L2 control structure for different control id */
|
||||
|
||||
int bpp; /* bytes per pixel */
|
||||
int vrfb_bpp; /* bytes per pixel with respect to VRFB */
|
||||
|
||||
struct vid_vrfb_dma vrfb_dma_tx;
|
||||
unsigned int smsshado_phy_addr[MAC_VRFB_CTXS];
|
||||
unsigned int smsshado_virt_addr[MAC_VRFB_CTXS];
|
||||
struct vrfb vrfb_context[MAC_VRFB_CTXS];
|
||||
bool vrfb_static_allocation;
|
||||
unsigned int smsshado_size;
|
||||
unsigned char pos;
|
||||
|
||||
int ps, vr_ps, line_length, first_int, field_id;
|
||||
enum v4l2_memory memory;
|
||||
struct videobuf_buffer *cur_frm, *next_frm;
|
||||
struct list_head dma_queue;
|
||||
u8 *queued_buf_addr[VIDEO_MAX_FRAME];
|
||||
u32 cropped_offset;
|
||||
s32 tv_field1_offset;
|
||||
void *isr_handle;
|
||||
|
||||
/* Buffer queue variables */
|
||||
struct omap_vout_device *vout;
|
||||
enum v4l2_buf_type type;
|
||||
struct videobuf_queue vbq;
|
||||
int io_allowed;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Return true if rotation is 90 or 270
|
||||
*/
|
||||
static inline int is_rotation_90_or_270(const struct omap_vout_device *vout)
|
||||
{
|
||||
return (vout->rotation == dss_rotation_90_degree ||
|
||||
vout->rotation == dss_rotation_270_degree);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if rotation is enabled
|
||||
*/
|
||||
static inline int is_rotation_enabled(const struct omap_vout_device *vout)
|
||||
{
|
||||
return vout->rotation || vout->mirror;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse the rotation degree if mirroring is enabled
|
||||
*/
|
||||
static inline int calc_rotation(const struct omap_vout_device *vout)
|
||||
{
|
||||
if (!vout->mirror)
|
||||
return vout->rotation;
|
||||
|
||||
switch (vout->rotation) {
|
||||
case dss_rotation_90_degree:
|
||||
return dss_rotation_270_degree;
|
||||
case dss_rotation_270_degree:
|
||||
return dss_rotation_90_degree;
|
||||
case dss_rotation_180_degree:
|
||||
return dss_rotation_0_degree;
|
||||
default:
|
||||
return dss_rotation_180_degree;
|
||||
}
|
||||
}
|
||||
|
||||
void omap_vout_free_buffers(struct omap_vout_device *vout);
|
||||
#endif /* ifndef OMAP_VOUTDEF_H */
|
339
drivers/media/platform/omap/omap_voutlib.c
Normal file
339
drivers/media/platform/omap/omap_voutlib.c
Normal file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* omap_voutlib.c
|
||||
*
|
||||
* Copyright (C) 2005-2010 Texas Instruments.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*
|
||||
* Based on the OMAP2 camera driver
|
||||
* Video-for-Linux (Version 2) camera capture driver for
|
||||
* the OMAP24xx camera controller.
|
||||
*
|
||||
* Author: Andy Lowe (source@mvista.com)
|
||||
*
|
||||
* Copyright (C) 2004 MontaVista Software, Inc.
|
||||
* Copyright (C) 2010 Texas Instruments.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#include "omap_voutlib.h"
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments");
|
||||
MODULE_DESCRIPTION("OMAP Video library");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Return the default overlay cropping rectangle in crop given the image
|
||||
* size in pix and the video display size in fbuf. The default
|
||||
* cropping rectangle is the largest rectangle no larger than the capture size
|
||||
* that will fit on the display. The default cropping rectangle is centered in
|
||||
* the image. All dimensions and offsets are rounded down to even numbers.
|
||||
*/
|
||||
void omap_vout_default_crop(struct v4l2_pix_format *pix,
|
||||
struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
|
||||
{
|
||||
crop->width = (pix->width < fbuf->fmt.width) ?
|
||||
pix->width : fbuf->fmt.width;
|
||||
crop->height = (pix->height < fbuf->fmt.height) ?
|
||||
pix->height : fbuf->fmt.height;
|
||||
crop->width &= ~1;
|
||||
crop->height &= ~1;
|
||||
crop->left = ((pix->width - crop->width) >> 1) & ~1;
|
||||
crop->top = ((pix->height - crop->height) >> 1) & ~1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_vout_default_crop);
|
||||
|
||||
/* Given a new render window in new_win, adjust the window to the
|
||||
* nearest supported configuration. The adjusted window parameters are
|
||||
* returned in new_win.
|
||||
* Returns zero if successful, or -EINVAL if the requested window is
|
||||
* impossible and cannot reasonably be adjusted.
|
||||
*/
|
||||
int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
|
||||
struct v4l2_window *new_win)
|
||||
{
|
||||
struct v4l2_rect try_win;
|
||||
|
||||
/* make a working copy of the new_win rectangle */
|
||||
try_win = new_win->w;
|
||||
|
||||
/* adjust the preview window so it fits on the display by clipping any
|
||||
* offscreen areas
|
||||
*/
|
||||
if (try_win.left < 0) {
|
||||
try_win.width += try_win.left;
|
||||
try_win.left = 0;
|
||||
}
|
||||
if (try_win.top < 0) {
|
||||
try_win.height += try_win.top;
|
||||
try_win.top = 0;
|
||||
}
|
||||
try_win.width = (try_win.width < fbuf->fmt.width) ?
|
||||
try_win.width : fbuf->fmt.width;
|
||||
try_win.height = (try_win.height < fbuf->fmt.height) ?
|
||||
try_win.height : fbuf->fmt.height;
|
||||
if (try_win.left + try_win.width > fbuf->fmt.width)
|
||||
try_win.width = fbuf->fmt.width - try_win.left;
|
||||
if (try_win.top + try_win.height > fbuf->fmt.height)
|
||||
try_win.height = fbuf->fmt.height - try_win.top;
|
||||
try_win.width &= ~1;
|
||||
try_win.height &= ~1;
|
||||
|
||||
if (try_win.width <= 0 || try_win.height <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* We now have a valid preview window, so go with it */
|
||||
new_win->w = try_win;
|
||||
new_win->field = V4L2_FIELD_ANY;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_vout_try_window);
|
||||
|
||||
/* Given a new render window in new_win, adjust the window to the
|
||||
* nearest supported configuration. The image cropping window in crop
|
||||
* will also be adjusted if necessary. Preference is given to keeping the
|
||||
* the window as close to the requested configuration as possible. If
|
||||
* successful, new_win, vout->win, and crop are updated.
|
||||
* Returns zero if successful, or -EINVAL if the requested preview window is
|
||||
* impossible and cannot reasonably be adjusted.
|
||||
*/
|
||||
int omap_vout_new_window(struct v4l2_rect *crop,
|
||||
struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
|
||||
struct v4l2_window *new_win)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = omap_vout_try_window(fbuf, new_win);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* update our preview window */
|
||||
win->w = new_win->w;
|
||||
win->field = new_win->field;
|
||||
win->chromakey = new_win->chromakey;
|
||||
|
||||
/* Adjust the cropping window to allow for resizing limitation */
|
||||
if (cpu_is_omap24xx()) {
|
||||
/* For 24xx limit is 8x to 1/2x scaling. */
|
||||
if ((crop->height/win->w.height) >= 2)
|
||||
crop->height = win->w.height * 2;
|
||||
|
||||
if ((crop->width/win->w.width) >= 2)
|
||||
crop->width = win->w.width * 2;
|
||||
|
||||
if (crop->width > 768) {
|
||||
/* The OMAP2420 vertical resizing line buffer is 768
|
||||
* pixels wide. If the cropped image is wider than
|
||||
* 768 pixels then it cannot be vertically resized.
|
||||
*/
|
||||
if (crop->height != win->w.height)
|
||||
crop->width = 768;
|
||||
}
|
||||
} else if (cpu_is_omap34xx()) {
|
||||
/* For 34xx limit is 8x to 1/4x scaling. */
|
||||
if ((crop->height/win->w.height) >= 4)
|
||||
crop->height = win->w.height * 4;
|
||||
|
||||
if ((crop->width/win->w.width) >= 4)
|
||||
crop->width = win->w.width * 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_vout_new_window);
|
||||
|
||||
/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
|
||||
* the nearest supported configuration. The image render window in win will
|
||||
* also be adjusted if necessary. The preview window is adjusted such that the
|
||||
* horizontal and vertical rescaling ratios stay constant. If the render
|
||||
* window would fall outside the display boundaries, the cropping rectangle
|
||||
* will also be adjusted to maintain the rescaling ratios. If successful, crop
|
||||
* and win are updated.
|
||||
* Returns zero if successful, or -EINVAL if the requested cropping rectangle is
|
||||
* impossible and cannot reasonably be adjusted.
|
||||
*/
|
||||
int omap_vout_new_crop(struct v4l2_pix_format *pix,
|
||||
struct v4l2_rect *crop, struct v4l2_window *win,
|
||||
struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
|
||||
{
|
||||
struct v4l2_rect try_crop;
|
||||
unsigned long vresize, hresize;
|
||||
|
||||
/* make a working copy of the new_crop rectangle */
|
||||
try_crop = *new_crop;
|
||||
|
||||
/* adjust the cropping rectangle so it fits in the image */
|
||||
if (try_crop.left < 0) {
|
||||
try_crop.width += try_crop.left;
|
||||
try_crop.left = 0;
|
||||
}
|
||||
if (try_crop.top < 0) {
|
||||
try_crop.height += try_crop.top;
|
||||
try_crop.top = 0;
|
||||
}
|
||||
try_crop.width = (try_crop.width < pix->width) ?
|
||||
try_crop.width : pix->width;
|
||||
try_crop.height = (try_crop.height < pix->height) ?
|
||||
try_crop.height : pix->height;
|
||||
if (try_crop.left + try_crop.width > pix->width)
|
||||
try_crop.width = pix->width - try_crop.left;
|
||||
if (try_crop.top + try_crop.height > pix->height)
|
||||
try_crop.height = pix->height - try_crop.top;
|
||||
|
||||
try_crop.width &= ~1;
|
||||
try_crop.height &= ~1;
|
||||
|
||||
if (try_crop.width <= 0 || try_crop.height <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
if (try_crop.height != win->w.height) {
|
||||
/* If we're resizing vertically, we can't support a
|
||||
* crop width wider than 768 pixels.
|
||||
*/
|
||||
if (try_crop.width > 768)
|
||||
try_crop.width = 768;
|
||||
}
|
||||
}
|
||||
/* vertical resizing */
|
||||
vresize = (1024 * try_crop.height) / win->w.height;
|
||||
if (cpu_is_omap24xx() && (vresize > 2048))
|
||||
vresize = 2048;
|
||||
else if (cpu_is_omap34xx() && (vresize > 4096))
|
||||
vresize = 4096;
|
||||
|
||||
win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
|
||||
if (win->w.height == 0)
|
||||
win->w.height = 2;
|
||||
if (win->w.height + win->w.top > fbuf->fmt.height) {
|
||||
/* We made the preview window extend below the bottom of the
|
||||
* display, so clip it to the display boundary and resize the
|
||||
* cropping height to maintain the vertical resizing ratio.
|
||||
*/
|
||||
win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
|
||||
if (try_crop.height == 0)
|
||||
try_crop.height = 2;
|
||||
}
|
||||
/* horizontal resizing */
|
||||
hresize = (1024 * try_crop.width) / win->w.width;
|
||||
if (cpu_is_omap24xx() && (hresize > 2048))
|
||||
hresize = 2048;
|
||||
else if (cpu_is_omap34xx() && (hresize > 4096))
|
||||
hresize = 4096;
|
||||
|
||||
win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
|
||||
if (win->w.width == 0)
|
||||
win->w.width = 2;
|
||||
if (win->w.width + win->w.left > fbuf->fmt.width) {
|
||||
/* We made the preview window extend past the right side of the
|
||||
* display, so clip it to the display boundary and resize the
|
||||
* cropping width to maintain the horizontal resizing ratio.
|
||||
*/
|
||||
win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
|
||||
if (try_crop.width == 0)
|
||||
try_crop.width = 2;
|
||||
}
|
||||
if (cpu_is_omap24xx()) {
|
||||
if ((try_crop.height/win->w.height) >= 2)
|
||||
try_crop.height = win->w.height * 2;
|
||||
|
||||
if ((try_crop.width/win->w.width) >= 2)
|
||||
try_crop.width = win->w.width * 2;
|
||||
|
||||
if (try_crop.width > 768) {
|
||||
/* The OMAP2420 vertical resizing line buffer is
|
||||
* 768 pixels wide. If the cropped image is wider
|
||||
* than 768 pixels then it cannot be vertically resized.
|
||||
*/
|
||||
if (try_crop.height != win->w.height)
|
||||
try_crop.width = 768;
|
||||
}
|
||||
} else if (cpu_is_omap34xx()) {
|
||||
if ((try_crop.height/win->w.height) >= 4)
|
||||
try_crop.height = win->w.height * 4;
|
||||
|
||||
if ((try_crop.width/win->w.width) >= 4)
|
||||
try_crop.width = win->w.width * 4;
|
||||
}
|
||||
/* update our cropping rectangle and we're done */
|
||||
*crop = try_crop;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_vout_new_crop);
|
||||
|
||||
/* Given a new format in pix and fbuf, crop and win
|
||||
* structures are initialized to default values. crop
|
||||
* is initialized to the largest window size that will fit on the display. The
|
||||
* crop window is centered in the image. win is initialized to
|
||||
* the same size as crop and is centered on the display.
|
||||
* All sizes and offsets are constrained to be even numbers.
|
||||
*/
|
||||
void omap_vout_new_format(struct v4l2_pix_format *pix,
|
||||
struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
|
||||
struct v4l2_window *win)
|
||||
{
|
||||
/* crop defines the preview source window in the image capture
|
||||
* buffer
|
||||
*/
|
||||
omap_vout_default_crop(pix, fbuf, crop);
|
||||
|
||||
/* win defines the preview target window on the display */
|
||||
win->w.width = crop->width;
|
||||
win->w.height = crop->height;
|
||||
win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
|
||||
win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_vout_new_format);
|
||||
|
||||
/*
|
||||
* Allocate buffers
|
||||
*/
|
||||
unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
|
||||
{
|
||||
u32 order, size;
|
||||
unsigned long virt_addr, addr;
|
||||
|
||||
size = PAGE_ALIGN(buf_size);
|
||||
order = get_order(size);
|
||||
virt_addr = __get_free_pages(GFP_KERNEL, order);
|
||||
addr = virt_addr;
|
||||
|
||||
if (virt_addr) {
|
||||
while (size > 0) {
|
||||
SetPageReserved(virt_to_page(addr));
|
||||
addr += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
*phys_addr = (u32) virt_to_phys((void *) virt_addr);
|
||||
return virt_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free buffers
|
||||
*/
|
||||
void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
|
||||
{
|
||||
u32 order, size;
|
||||
unsigned long addr = virtaddr;
|
||||
|
||||
size = PAGE_ALIGN(buf_size);
|
||||
order = get_order(size);
|
||||
|
||||
while (size > 0) {
|
||||
ClearPageReserved(virt_to_page(addr));
|
||||
addr += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
free_pages((unsigned long) virtaddr, order);
|
||||
}
|
36
drivers/media/platform/omap/omap_voutlib.h
Normal file
36
drivers/media/platform/omap/omap_voutlib.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* omap_voutlib.h
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OMAP_VOUTLIB_H
|
||||
#define OMAP_VOUTLIB_H
|
||||
|
||||
void omap_vout_default_crop(struct v4l2_pix_format *pix,
|
||||
struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
|
||||
|
||||
int omap_vout_new_crop(struct v4l2_pix_format *pix,
|
||||
struct v4l2_rect *crop, struct v4l2_window *win,
|
||||
struct v4l2_framebuffer *fbuf,
|
||||
const struct v4l2_rect *new_crop);
|
||||
|
||||
int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
|
||||
struct v4l2_window *new_win);
|
||||
|
||||
int omap_vout_new_window(struct v4l2_rect *crop,
|
||||
struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
|
||||
struct v4l2_window *new_win);
|
||||
|
||||
void omap_vout_new_format(struct v4l2_pix_format *pix,
|
||||
struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
|
||||
struct v4l2_window *win);
|
||||
unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr);
|
||||
void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size);
|
||||
#endif /* #ifndef OMAP_VOUTLIB_H */
|
||||
|
Reference in New Issue
Block a user