diff options
author | Koen Kooi <koen@openembedded.org> | 2009-09-04 15:32:30 +0200 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2009-09-04 15:32:30 +0200 |
commit | 881f92e3409f67f70cffd5cfaca0de8248729145 (patch) | |
tree | 49f15add251b6ded5b2c5efc29f5603b76619e0e /recipes/linux/linux-omap-2.6.31/dss2 | |
parent | eff28b3b4ec8309ac1d51d98b8bfc9f5d48ed43f (diff) |
linux-omap git: another checkpoint
* add V4l2 interfaces to DSS2
* add back MADC driver
* add zippy support for beagleboard
* add DSS2 for omap3evm
Diffstat (limited to 'recipes/linux/linux-omap-2.6.31/dss2')
4 files changed, 3827 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch b/recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch new file mode 100644 index 0000000000..9a4ea8b9ad --- /dev/null +++ b/recipes/linux/linux-omap-2.6.31/dss2/0001-OMAP3-Enable-DSS2-for-OMAP3EVM-board.patch @@ -0,0 +1,387 @@ +From 798f9b1bc478c7ded724fc190c65e413c2401314 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Tue, 11 Aug 2009 15:52:04 +0530 +Subject: [PATCH 1/5] OMAP3: Enable DSS2 for OMAP3EVM board + +Tested - + - Validated all three outut interfaces (LCD, DVI and TV) +TODO: + - Support for Backlight control range (0 - 100) + - Enable selection for both S-Video and Composite TV out + - DVI color (VPLL2_DEV_GRP should be equal to 0x7) + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + arch/arm/configs/omap3_evm_defconfig | 51 +++++++- + arch/arm/mach-omap2/board-omap3evm.c | 234 ++++++++++++++++++++++++++++++++-- + 2 files changed, 273 insertions(+), 12 deletions(-) + +diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig +index d5ff477..ba395a2 100644 +--- a/arch/arm/configs/omap3_evm_defconfig ++++ b/arch/arm/configs/omap3_evm_defconfig +@@ -903,7 +903,56 @@ CONFIG_DAB=y + # + # CONFIG_VGASTATE is not set + CONFIG_VIDEO_OUTPUT_CONTROL=m +-# CONFIG_FB is not set ++CONFIG_FB=y ++# CONFIG_FIRMWARE_EDID is not set ++# CONFIG_FB_DDC is not set ++# CONFIG_FB_BOOT_VESA_SUPPORT is not set ++CONFIG_FB_CFB_FILLRECT=y ++CONFIG_FB_CFB_COPYAREA=y ++CONFIG_FB_CFB_IMAGEBLIT=y ++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set ++# CONFIG_FB_SYS_FILLRECT is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_SYS_FOPS is not set ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++# CONFIG_FB_MODE_HELPERS is not set ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_S1D13XXX is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FB_METRONOME is not set ++# CONFIG_FB_MB862XX is not set ++# CONFIG_FB_BROADSHEET is not set ++# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set ++CONFIG_OMAP2_VRAM=y ++CONFIG_OMAP2_VRFB=y ++CONFIG_OMAP2_DSS=y ++CONFIG_OMAP2_VRAM_SIZE=4 ++# CONFIG_OMAP2_DSS_DEBUG_SUPPORT is not set ++# CONFIG_OMAP2_DSS_RFBI is not set ++CONFIG_OMAP2_DSS_VENC=y ++# CONFIG_OMAP2_DSS_SDI is not set ++# CONFIG_OMAP2_DSS_DSI is not set ++# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set ++CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 ++CONFIG_FB_OMAP2=y ++# CONFIG_FB_OMAP2_DEBUG_SUPPORT is not set ++# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set ++CONFIG_FB_OMAP2_NUM_FBS=3 ++ ++# ++# OMAP2/3 Display Device Drivers ++# ++CONFIG_PANEL_GENERIC=y ++# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set ++CONFIG_PANEL_SHARP_LS037V7DW01=y + # CONFIG_BACKLIGHT_LCD_SUPPORT is not set + + # +diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c +index c0cb29d..0bc26b3 100644 +--- a/arch/arm/mach-omap2/board-omap3evm.c ++++ b/arch/arm/mach-omap2/board-omap3evm.c +@@ -22,6 +22,7 @@ + #include <linux/input.h> + #include <linux/leds.h> + ++#include <linux/regulator/machine.h> + #include <linux/spi/spi.h> + #include <linux/spi/ads7846.h> + #include <linux/i2c/twl4030.h> +@@ -38,6 +39,7 @@ + #include <mach/common.h> + #include <mach/mcspi.h> + #include <mach/keypad.h> ++#include <mach/display.h> + + #include "sdram-micron-mt46h32m32lf-6.h" + #include "mmc-twl4030.h" +@@ -91,6 +93,174 @@ static inline void __init omap3evm_init_smc911x(void) + + gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ); + } ++/* ++ * OMAP3EVM LCD Panel control signals ++ */ ++#define OMAP3EVM_LCD_PANEL_LR 2 ++#define OMAP3EVM_LCD_PANEL_UD 3 ++#define OMAP3EVM_LCD_PANEL_INI 152 ++#define OMAP3EVM_LCD_PANEL_ENVDD 153 ++#define OMAP3EVM_LCD_PANEL_QVGA 154 ++#define OMAP3EVM_LCD_PANEL_RESB 155 ++#define OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO 210 ++#define OMAP3EVM_DVI_PANEL_EN_GPIO 199 ++ ++static int lcd_enabled; ++static int dvi_enabled; ++ ++static void __init omap3_evm_display_init(void) ++{ ++ int r; ++ r = gpio_request(OMAP3EVM_LCD_PANEL_RESB, "lcd_panel_resb"); ++ if (r) { ++ printk(KERN_ERR "failed to get lcd_panel_resb\n"); ++ return; ++ } ++ gpio_direction_output(OMAP3EVM_LCD_PANEL_RESB, 1); ++ ++ r = gpio_request(OMAP3EVM_LCD_PANEL_INI, "lcd_panel_ini"); ++ if (r) { ++ printk(KERN_ERR "failed to get lcd_panel_ini\n"); ++ goto err_1; ++ } ++ gpio_direction_output(OMAP3EVM_LCD_PANEL_INI, 1); ++ ++ r = gpio_request(OMAP3EVM_LCD_PANEL_QVGA, "lcd_panel_qvga"); ++ if (r) { ++ printk(KERN_ERR "failed to get lcd_panel_qvga\n"); ++ goto err_2; ++ } ++ gpio_direction_output(OMAP3EVM_LCD_PANEL_QVGA, 0); ++ ++ r = gpio_request(OMAP3EVM_LCD_PANEL_LR, "lcd_panel_lr"); ++ if (r) { ++ printk(KERN_ERR "failed to get lcd_panel_lr\n"); ++ goto err_3; ++ } ++ gpio_direction_output(OMAP3EVM_LCD_PANEL_LR, 1); ++ ++ r = gpio_request(OMAP3EVM_LCD_PANEL_UD, "lcd_panel_ud"); ++ if (r) { ++ printk(KERN_ERR "failed to get lcd_panel_ud\n"); ++ goto err_4; ++ } ++ gpio_direction_output(OMAP3EVM_LCD_PANEL_UD, 1); ++ ++ r = gpio_request(OMAP3EVM_LCD_PANEL_ENVDD, "lcd_panel_envdd"); ++ if (r) { ++ printk(KERN_ERR "failed to get lcd_panel_envdd\n"); ++ goto err_5; ++ } ++ ++ return; ++ ++err_5: ++ gpio_free(OMAP3EVM_LCD_PANEL_UD); ++err_4: ++ gpio_free(OMAP3EVM_LCD_PANEL_LR); ++err_3: ++ gpio_free(OMAP3EVM_LCD_PANEL_QVGA); ++err_2: ++ gpio_free(OMAP3EVM_LCD_PANEL_INI); ++err_1: ++ gpio_free(OMAP3EVM_LCD_PANEL_RESB); ++ ++} ++ ++static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev) ++{ ++ if (dvi_enabled) { ++ printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); ++ return -EINVAL; ++ } ++ ++ gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 0); ++ gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1); ++ lcd_enabled = 1; ++ return 0; ++} ++ ++static void omap3_evm_disable_lcd(struct omap_dss_device *dssdev) ++{ ++ gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 1); ++ gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0); ++ lcd_enabled = 0; ++} ++ ++static struct omap_dss_device omap3_evm_lcd_device = { ++ .type = OMAP_DISPLAY_TYPE_DPI, ++ .name = "lcd", ++ .driver_name = "sharp_ls_panel", ++ .phy.dpi.data_lines = 18, ++ .platform_enable = omap3_evm_enable_lcd, ++ .platform_disable = omap3_evm_disable_lcd, ++}; ++ ++static int omap3_evm_enable_tv(struct omap_dss_device *dssdev) ++{ ++ return 0; ++} ++ ++static void omap3_evm_disable_tv(struct omap_dss_device *dssdev) ++{ ++} ++ ++static struct omap_dss_device omap3_evm_tv_device = { ++ .type = OMAP_DISPLAY_TYPE_VENC, ++ .name = "tv", ++ .driver_name = "venc", ++ .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, ++ .platform_enable = omap3_evm_enable_tv, ++ .platform_disable = omap3_evm_disable_tv, ++}; ++ ++static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev) ++{ ++ if (lcd_enabled) { ++ printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); ++ return -EINVAL; ++ } ++ ++ gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 1); ++ dvi_enabled = 1; ++ ++ return 0; ++} ++ ++static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev) ++{ ++ gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 0); ++ dvi_enabled = 0; ++} ++ ++static struct omap_dss_device omap3_evm_dvi_device = { ++ .type = OMAP_DISPLAY_TYPE_DPI, ++ .name = "dvi", ++ .driver_name = "generic_panel", ++ .phy.dpi.data_lines = 24, ++ .platform_enable = omap3_evm_enable_dvi, ++ .platform_disable = omap3_evm_disable_dvi, ++}; ++ ++static struct omap_dss_device *omap3_evm_dss_devices[] = { ++ &omap3_evm_lcd_device, ++ &omap3_evm_tv_device, ++ &omap3_evm_dvi_device, ++}; ++ ++static struct omap_dss_board_info omap3_evm_dss_data = { ++ .num_devices = ARRAY_SIZE(omap3_evm_dss_devices), ++ .devices = omap3_evm_dss_devices, ++ .default_device = &omap3_evm_lcd_device, ++}; ++ ++static struct platform_device omap3_evm_dss_device = { ++ .name = "omapdss", ++ .id = -1, ++ .dev = { ++ .platform_data = &omap3_evm_dss_data, ++ }, ++}; + + static struct omap_uart_platform_data omap3_evm_uart_config __initdata = { + .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), +@@ -143,6 +313,14 @@ static int omap3evm_twl_gpio_setup(struct device *dev, + * the P2 connector; notably LEDA for the LCD backlight. + */ + ++ /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */ ++ gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL"); ++ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0); ++ ++ /* gpio + 7 == DVI Enable */ ++ gpio_request(gpio + 7, "EN_DVI"); ++ gpio_direction_output(gpio + 7, 0); ++ + /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + +@@ -194,6 +372,47 @@ static struct twl4030_madc_platform_data omap3evm_madc_data = { + .irq_line = 1, + }; + ++static struct regulator_consumer_supply omap3_evm_vdda_dac_supply = { ++ .supply = "vdda_dac", ++ .dev = &omap3_evm_dss_device.dev, ++}; ++ ++/* VDAC for DSS driving S-Video */ ++static struct regulator_init_data omap3_evm_vdac = { ++ .constraints = { ++ .min_uV = 1800000, ++ .max_uV = 1800000, ++ .apply_uV = true, ++ .valid_modes_mask = REGULATOR_MODE_NORMAL ++ | REGULATOR_MODE_STANDBY, ++ .valid_ops_mask = REGULATOR_CHANGE_MODE ++ | REGULATOR_CHANGE_STATUS, ++ }, ++ .num_consumer_supplies = 1, ++ .consumer_supplies = &omap3_evm_vdda_dac_supply, ++}; ++ ++/* VPLL2 for digital video outputs */ ++static struct regulator_consumer_supply omap3_evm_vpll2_supply = { ++ .supply = "vdvi", ++ .dev = &omap3_evm_lcd_device.dev, ++}; ++ ++static struct regulator_init_data omap3_evm_vpll2 = { ++ .constraints = { ++ .name = "VDVI", ++ .min_uV = 1800000, ++ .max_uV = 1800000, ++ .apply_uV = true, ++ .valid_modes_mask = REGULATOR_MODE_NORMAL ++ | REGULATOR_MODE_STANDBY, ++ .valid_ops_mask = REGULATOR_CHANGE_MODE ++ | REGULATOR_CHANGE_STATUS, ++ }, ++ .num_consumer_supplies = 1, ++ .consumer_supplies = &omap3_evm_vpll2_supply, ++}; ++ + static struct twl4030_platform_data omap3evm_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, +@@ -203,6 +422,8 @@ static struct twl4030_platform_data omap3evm_twldata = { + .madc = &omap3evm_madc_data, + .usb = &omap3evm_usb_data, + .gpio = &omap3evm_gpio_data, ++ .vdac = &omap3_evm_vdac, ++ .vpll2 = &omap3_evm_vpll2, + }; + + static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = { +@@ -223,15 +444,6 @@ static int __init omap3_evm_i2c_init(void) + return 0; + } + +-static struct platform_device omap3_evm_lcd_device = { +- .name = "omap3evm_lcd", +- .id = -1, +-}; +- +-static struct omap_lcd_config omap3_evm_lcd_config __initdata = { +- .ctrl_name = "internal", +-}; +- + static void ads7846_dev_init(void) + { + if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0) +@@ -287,11 +499,10 @@ static void __init omap3_evm_init_irq(void) + } + + static struct omap_board_config_kernel omap3_evm_config[] __initdata = { +- { OMAP_TAG_LCD, &omap3_evm_lcd_config }, + }; + + static struct platform_device *omap3_evm_devices[] __initdata = { +- &omap3_evm_lcd_device, ++ &omap3_evm_dss_device, + &omap3evm_smc911x_device, + }; + +@@ -314,6 +525,7 @@ static void __init omap3_evm_init(void) + usb_musb_init(); + usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, true, true, 57, 61); + ads7846_dev_init(); ++ omap3_evm_display_init(); + } + + static void __init omap3_evm_map_io(void) +-- +1.6.2.4 + diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch b/recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch new file mode 100644 index 0000000000..f05929088f --- /dev/null +++ b/recipes/linux/linux-omap-2.6.31/dss2/0002-V4L2-Added-New-V4L2-CIDs-for-omap-devices-V4L2-IOCT.patch @@ -0,0 +1,152 @@ +From bcb3cd3f6dd8d80a4f7cc524b769d711addfc48d Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Wed, 22 Jul 2009 23:49:29 +0530 +Subject: [PATCH 2/5] V4L2: Added New V4L2 CIDs for omap devices V4L2 IOCTL + +Changes - + - Renamed V4L2_CID_ROTATION to V4L2_CID_ROTATE + - Implementationadded for VIDIOC_S/G_COLOR_SPACE_CONV + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + drivers/media/video/v4l2-ioctl.c | 19 +++++++++++++++++++ + include/linux/videodev2.h | 21 ++++++++++++++++++--- + include/media/v4l2-ioctl.h | 4 ++++ + 3 files changed, 41 insertions(+), 3 deletions(-) + +diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c +index f2afc4e..74d2ed9 100644 +--- a/drivers/media/video/v4l2-ioctl.c ++++ b/drivers/media/video/v4l2-ioctl.c +@@ -278,6 +278,8 @@ static const char *v4l2_ioctls[] = { + [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", + [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", + #endif ++ [_IOC_NR(VIDIOC_S_COLOR_SPACE_CONV)] = "VIDIOC_S_COLOR_SPACE_CONV", ++ [_IOC_NR(VIDIOC_G_COLOR_SPACE_CONV)] = "VIDIOC_G_COLOR_SPACE_CONV", + }; + #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) + +@@ -1784,6 +1786,23 @@ static long __video_do_ioctl(struct file *file, + break; + } + ++ /*---------------Color space conversion------------------------------*/ ++ case VIDIOC_S_COLOR_SPACE_CONV: ++ { ++ struct v4l2_color_space_conversion *p = arg; ++ if (!ops->vidioc_s_color_space_conv) ++ break; ++ ret = ops->vidioc_s_color_space_conv(file, fh, p); ++ break; ++ } ++ case VIDIOC_G_COLOR_SPACE_CONV: ++ { ++ struct v4l2_color_space_conversion *p = arg; ++ if (!ops->vidioc_g_color_space_conv) ++ break; ++ ret = ops->vidioc_g_color_space_conv(file, fh, p); ++ break; ++ } + default: + { + if (!ops->vidioc_default) +diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h +index 74f1687..78e8158 100644 +--- a/include/linux/videodev2.h ++++ b/include/linux/videodev2.h +@@ -554,6 +554,7 @@ struct v4l2_framebuffer { + #define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010 + #define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020 + #define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040 ++#define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080 + /* Flags for the 'flags' field. */ + #define V4L2_FBUF_FLAG_PRIMARY 0x0001 + #define V4L2_FBUF_FLAG_OVERLAY 0x0002 +@@ -561,6 +562,7 @@ struct v4l2_framebuffer { + #define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008 + #define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010 + #define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020 ++#define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040 + + struct v4l2_clip { + struct v4l2_rect c; +@@ -902,6 +904,8 @@ enum v4l2_colorfx { + + /* last CID + 1 */ + #define V4L2_CID_LASTP1 (V4L2_CID_BASE+33) ++#define V4L2_CID_ROTATE (V4L2_CID_BASE+34) ++#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35) + + /* MPEG-class control IDs defined by V4L2 */ + #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) +@@ -1213,6 +1217,18 @@ struct v4l2_hw_freq_seek { + }; + + /* ++ * Color conversion ++ * User needs to pass pointer to color conversion matrix ++ * defined by hardware ++ */ ++struct v4l2_color_space_conversion { ++ __s32 coefficients[3][3]; ++ __s32 const_factor; ++ __s32 input_offs[3]; ++ __s32 output_offs[3]; ++}; ++ ++/* + * A U D I O + */ + struct v4l2_audio { +@@ -1265,7 +1281,6 @@ struct v4l2_enc_idx { + struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES]; + }; + +- + #define V4L2_ENC_CMD_START (0) + #define V4L2_ENC_CMD_STOP (1) + #define V4L2_ENC_CMD_PAUSE (2) +@@ -1286,7 +1301,6 @@ struct v4l2_encoder_cmd { + + #endif + +- + /* + * D A T A S E R V I C E S ( V B I ) + * +@@ -1423,7 +1437,6 @@ struct v4l2_format { + } fmt; + }; + +- + /* Stream type-dependent parameters + */ + struct v4l2_streamparm { +@@ -1551,6 +1564,8 @@ struct v4l2_dbg_chip_ident { + #endif + + #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) ++#define VIDIOC_S_COLOR_SPACE_CONV _IOW('V', 83, struct v4l2_color_space_conversion) ++#define VIDIOC_G_COLOR_SPACE_CONV _IOR('V', 84, struct v4l2_color_space_conversion) + /* Reminder: when adding new ioctls please add support for them to + drivers/media/video/v4l2-compat-ioctl32.c as well! */ + +diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h +index 7a4529d..6f46d09 100644 +--- a/include/media/v4l2-ioctl.h ++++ b/include/media/v4l2-ioctl.h +@@ -242,6 +242,10 @@ struct v4l2_ioctl_ops { + /* For other private ioctls */ + long (*vidioc_default) (struct file *file, void *fh, + int cmd, void *arg); ++ int (*vidioc_s_color_space_conv) (struct file *file, void *fh, ++ struct v4l2_color_space_conversion *a); ++ int (*vidioc_g_color_space_conv) (struct file *file, void *fh, ++ struct v4l2_color_space_conversion *a); + }; + + +-- +1.6.2.4 + diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch b/recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch new file mode 100644 index 0000000000..0fd8135bb1 --- /dev/null +++ b/recipes/linux/linux-omap-2.6.31/dss2/0003-V4L2-Updated-v4l2_common-for-new-V4L2-CIDs.patch @@ -0,0 +1,40 @@ +From 691a4534df820b6c90a37de1941197efbe86984a Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Fri, 21 Aug 2009 11:19:46 +0530 +Subject: [PATCH 3/5] V4L2: Updated v4l2_common for new V4L2 CIDs. + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + drivers/media/video/v4l2-common.c | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c +index b91d66a..5dae426 100644 +--- a/drivers/media/video/v4l2-common.c ++++ b/drivers/media/video/v4l2-common.c +@@ -421,6 +421,8 @@ const char *v4l2_ctrl_get_name(u32 id) + case V4L2_CID_CHROMA_AGC: return "Chroma AGC"; + case V4L2_CID_COLOR_KILLER: return "Color Killer"; + case V4L2_CID_COLORFX: return "Color Effects"; ++ case V4L2_CID_ROTATE: return "Rotate"; ++ case V4L2_CID_BG_COLOR: return "Background color"; + + /* MPEG controls */ + case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls"; +@@ -546,6 +548,13 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste + qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + min = max = step = def = 0; + break; ++ case V4L2_CID_BG_COLOR: ++ qctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ step = 1; ++ min = 0; ++ /* Max is calculated as RGB888 that is 2^12*/ ++ max = 0xFFFFFF; ++ break; + default: + qctrl->type = V4L2_CTRL_TYPE_INTEGER; + break; +-- +1.6.2.4 + diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch b/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch new file mode 100644 index 0000000000..5db9c65d41 --- /dev/null +++ b/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP2-3-V4L2-Add-support-for-OMAP2-3-V4L2-driver-on.patch @@ -0,0 +1,3248 @@ +From 2ae2dbacb82c5f0cb0fbcde7b49510d5cf2d45b5 Mon Sep 17 00:00:00 2001 +From: Vaibhav Hiremath <hvaibhav@ti.com> +Date: Wed, 12 Aug 2009 19:38:30 +0530 +Subject: [PATCH 4/5] OMAP2/3 V4L2: Add support for OMAP2/3 V4L2 driver on top of DSS2 + +Features Supported - + 1. Provides V4L2 user interface for the video pipelines of DSS + 2. Basic streaming working on LCD, DVI and TV. + 3. Works on latest DSS2 library from Tomi + 4. Support for various pixel formats like YUV, UYVY, RGB32, RGB24, + RGB565 + 5. Supports Alpha blending. + 6. Supports Color keying both source and destination. + 7. Supports rotation. + 8. Supports cropping. + 9. Supports Background color setting. + +TODO: + 1. Complete Testing is pending, only basic test passed. + +Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> +--- + arch/arm/plat-omap/devices.c | 29 + + drivers/media/video/Kconfig | 12 + + drivers/media/video/Makefile | 2 + + drivers/media/video/omap/Kconfig | 22 + + drivers/media/video/omap/Makefile | 2 + + drivers/media/video/omap/omap_vout.c | 2623 +++++++++++++++++++++++++++++++ + drivers/media/video/omap/omap_voutdef.h | 148 ++ + drivers/media/video/omap/omap_voutlib.c | 258 +++ + drivers/media/video/omap/omap_voutlib.h | 34 + + 9 files changed, 3130 insertions(+), 0 deletions(-) + create mode 100644 drivers/media/video/omap/Kconfig + create mode 100644 drivers/media/video/omap/Makefile + create mode 100644 drivers/media/video/omap/omap_vout.c + create mode 100644 drivers/media/video/omap/omap_voutdef.h + create mode 100644 drivers/media/video/omap/omap_voutlib.c + create mode 100644 drivers/media/video/omap/omap_voutlib.h + +diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c +index a64b692..8b6a9a0 100644 +--- a/arch/arm/plat-omap/devices.c ++++ b/arch/arm/plat-omap/devices.c +@@ -357,6 +357,34 @@ static void omap_init_rng(void) + static inline void omap_init_rng(void) {} + #endif + ++/*---------------------------------------------------------------------------*/ ++ ++#if defined(CONFIG_VIDEO_OMAP_VIDEOOUT) || \ ++ defined(CONFIG_VIDEO_OMAP_VIDEOOUT_MODULE) ++#ifdef CONFIG_FB_OMAP2 ++static struct resource omap3evm_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = { ++}; ++#else ++static struct resource omap3evm_vout_resource[2] = { ++}; ++#endif ++ ++static struct platform_device omap3evm_vout_device = { ++ .name = "omap_vout", ++ .num_resources = ARRAY_SIZE(omap3evm_vout_resource), ++ .resource = &omap3evm_vout_resource[0], ++ .id = -1, ++}; ++static void omap_init_vout(void) ++{ ++ (void) platform_device_register(&omap3evm_vout_device); ++} ++#else ++static inline void omap_init_vout(void) {} ++#endif ++ ++/*---------------------------------------------------------------------------*/ ++ + /* + * This gets called after board-specific INIT_MACHINE, and initializes most + * on-chip peripherals accessible on this board (except for few like USB): +@@ -387,6 +415,7 @@ static int __init omap_init_devices(void) + omap_init_uwire(); + omap_init_wdt(); + omap_init_rng(); ++ omap_init_vout(); + return 0; + } + arch_initcall(omap_init_devices); +diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig +index dcf9fa9..afb4478 100644 +--- a/drivers/media/video/Kconfig ++++ b/drivers/media/video/Kconfig +@@ -718,6 +718,18 @@ config VIDEO_CAFE_CCIC + CMOS camera controller. This is the controller found on first- + generation OLPC systems. + ++config VIDEO_OMAP3 ++ bool "OMAP2/OMAP3 Camera and V4L2-DSS drivers" ++ select VIDEOBUF_GEN ++ select VIDEOBUF_DMA_SG ++ select OMAP2_DSS ++ depends on VIDEO_DEV && (ARCH_OMAP24XX || ARCH_OMAP34XX) ++ default y ++ ---help--- ++ V4L2 DSS and Camera driver support for OMAP2/3 based boards. ++ ++source "drivers/media/video/omap/Kconfig" ++ + config SOC_CAMERA + tristate "SoC camera support" + depends on VIDEO_V4L2 && HAS_DMA && I2C +diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile +index 9f2e321..36040b9 100644 +--- a/drivers/media/video/Makefile ++++ b/drivers/media/video/Makefile +@@ -117,6 +117,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o + + obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o + ++obj-$(CONFIG_VIDEO_OMAP3) += omap/ ++ + obj-$(CONFIG_USB_DABUSB) += dabusb.o + obj-$(CONFIG_USB_OV511) += ov511.o + obj-$(CONFIG_USB_SE401) += se401.o +diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig +new file mode 100644 +index 0000000..5b86db3 +--- /dev/null ++++ b/drivers/media/video/omap/Kconfig +@@ -0,0 +1,22 @@ ++config VIDEO_OMAP_VIDEOOUT ++ tristate "OMAP Video out driver" ++ select VIDEOBUF_DMA_SG ++ select VIDEOBUF_GEN ++ depends on VIDEO_OMAP3 ++ default VIDEO_OMAP3 ++ ++choice ++ prompt "TV Mode" ++ default NTSC_M ++ ++config NTSC_M ++ bool "Use NTSC_M mode" ++ help ++ Select this option if you want NTSC_M mode on TV ++ ++config PAL_BDGHI ++ bool "Use PAL_BDGHI mode" ++ help ++ Select this option if you want PAL_BDGHI mode on TV ++ ++endchoice +diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile +new file mode 100644 +index 0000000..18854c7 +--- /dev/null ++++ b/drivers/media/video/omap/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += omap_vout.o omap_voutlib.o ++ +diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c +new file mode 100644 +index 0000000..7e15db2 +--- /dev/null ++++ b/drivers/media/video/omap/omap_vout.c +@@ -0,0 +1,2623 @@ ++/* ++ * drivers/media/video/omap/omap_vout.c ++ * ++ * Copyright (C) 2005-2009 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. ++ * ++ * Leveraged code from 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) 2009 Texas Instruments. ++ * ++ * History: ++ * 20-APR-2006 Khasim Modified VRFB based Rotation, ++ * The image data is always read from 0 degree ++ * view and written ++ * to the virtual space of desired rotation angle ++ * 4-DEC-2006 Jian Changed to support better memory management ++ * ++ * 17-Nov-2008 Hardik Changed to used the new DSS paches by Tomi ++ * Changed driver to use video_ioctl2 ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/fs.h> ++#include <linux/kernel.h> ++#include <linux/vmalloc.h> ++#include <linux/interrupt.h> ++#include <linux/kdev_t.h> ++#include <linux/types.h> ++#include <linux/wait.h> ++#include <linux/videodev2.h> ++#include <linux/platform_device.h> ++#include <linux/dma-mapping.h> ++#include <linux/irq.h> ++ ++#include <media/videobuf-dma-sg.h> ++#include <media/v4l2-dev.h> ++#include <media/v4l2-ioctl.h> ++#include <media/v4l2-common.h> ++#include <media/v4l2-device.h> ++ ++#include <asm/processor.h> ++#include <mach/dma.h> ++#include <mach/vram.h> ++#include <mach/vrfb.h> ++#include <mach/display.h> ++ ++#include "omap_voutlib.h" ++#include "omap_voutdef.h" ++ ++MODULE_AUTHOR("Texas Instruments."); ++MODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); ++MODULE_LICENSE("GPL"); ++ ++#define OMAP_VIDEO1 0 ++#define OMAP_VIDEO2 1 ++ ++/* configuration macros */ ++#define VOUT_NAME "omap_vout" ++ ++#define QQVGA_WIDTH 160 ++#define QQVGA_HEIGHT 120 ++ ++#define NUM_OF_VIDEO_CHANNELS 2 ++ ++#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 DMA_CHAN_ALLOTED 1 ++#define DMA_CHAN_NOT_ALLOTED 0 ++#define MAX_PIXELS_PER_LINE 2048 ++#define VRFB_TX_TIMEOUT 1000 ++ ++/* IRQ Bits mask of DSS */ ++#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4) ++ ++static struct videobuf_queue_ops video_vbq_ops; ++ ++static u32 video1_numbuffers = 3; ++static u32 video2_numbuffers = 3; ++static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE; ++static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE; ++static u32 vid1_static_vrfb_alloc; ++static u32 vid2_static_vrfb_alloc; ++static int debug; ++ ++/* Module parameters */ ++module_param(video1_numbuffers, uint, S_IRUGO); ++MODULE_PARM_DESC(video1_numbuffers, ++ "Number of buffers to be allocated at init time for Video1 device."); ++ ++module_param(video2_numbuffers, uint, S_IRUGO); ++MODULE_PARM_DESC(video2_numbuffers, ++ "Number of buffers to be allocated at init time for Video2 device."); ++ ++module_param(video1_bufsize, uint, S_IRUGO); ++MODULE_PARM_DESC(video1_bufsize, ++ "Size of the buffer to be allocated for video1 device"); ++ ++module_param(video2_bufsize, uint, S_IRUGO); ++MODULE_PARM_DESC(video2_bufsize, ++ "Size of the buffer to be allocated for video2 device"); ++ ++module_param(vid1_static_vrfb_alloc, bool, S_IRUGO); ++MODULE_PARM_DESC(vid1_static_vrfb_alloc, ++ "Static allocation of the VRFB buffer for video1 device"); ++ ++module_param(vid2_static_vrfb_alloc, bool, S_IRUGO); ++MODULE_PARM_DESC(vid2_static_vrfb_alloc, ++ "Static allocation of the VRFB buffer for video2 device"); ++ ++module_param(debug, bool, S_IRUGO); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++/* Local Helper functions */ ++static void omap_vout_isr(void *arg, unsigned int irqstatus); ++static void omap_vout_cleanup_device(struct omap_vout_device *vout); ++/* ++ * Maximum amount of memory to use for rendering buffers. ++ * Default is enough to four (RGB24) DVI 720P buffers. ++ */ ++#define MAX_ALLOWED_VIDBUFFERS 4 ++ ++/* list of image formats supported by OMAP2 video pipelines */ ++const static struct v4l2_fmtdesc omap_formats[] = { ++ { ++ /* Note: V4L2 defines RGB565 as: ++ * ++ * Byte 0 Byte 1 ++ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 ++ * ++ * We interpret RGB565 as: ++ * ++ * Byte 0 Byte 1 ++ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 ++ */ ++ .description = "RGB565, le", ++ .pixelformat = V4L2_PIX_FMT_RGB565, ++ }, ++ { ++ /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use ++ * this for RGB24 unpack mode, the last 8 bits are ignored ++ * */ ++ .description = "RGB32, le", ++ .pixelformat = V4L2_PIX_FMT_RGB32, ++ }, ++ { ++ /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use ++ * this for RGB24 packed mode ++ * ++ */ ++ .description = "RGB24, le", ++ .pixelformat = V4L2_PIX_FMT_RGB24, ++ }, ++ { ++ .description = "YUYV (YUV 4:2:2), packed", ++ .pixelformat = V4L2_PIX_FMT_YUYV, ++ }, ++ { ++ .description = "UYVY, packed", ++ .pixelformat = V4L2_PIX_FMT_UYVY, ++ }, ++}; ++ ++#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) ++ ++/* Allocate buffers */ ++static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr) ++{ ++ unsigned long virt_addr, addr; ++ u32 order, size; ++ ++ size = PAGE_ALIGN(buf_size); ++ order = get_order(size); ++ virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, 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 */ ++static void omap_vout_free_buffer(unsigned long virtaddr, u32 phys_addr, ++ u32 buf_size) ++{ ++ unsigned long addr = virtaddr; ++ u32 order, size; ++ ++ 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); ++} ++ ++/* 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_phy_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; ++} ++ ++/* Try format */ ++static int omap_vout_try_format(struct v4l2_pix_format *pix) ++{ ++ int ifmt, bpp = 0; ++ ++ pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT, ++ (u32)VID_MAX_HEIGHT); ++ pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH); ++ ++ for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) { ++ if (pix->pixelformat == omap_formats[ifmt].pixelformat) ++ break; ++ } ++ ++ if (ifmt == NUM_OUTPUT_FORMATS) ++ ifmt = 0; ++ ++ pix->pixelformat = omap_formats[ifmt].pixelformat; ++ pix->field = V4L2_FIELD_ANY; ++ pix->priv = 0; ++ ++ switch (pix->pixelformat) { ++ case V4L2_PIX_FMT_YUYV: ++ case V4L2_PIX_FMT_UYVY: ++ default: ++ pix->colorspace = V4L2_COLORSPACE_JPEG; ++ bpp = YUYV_BPP; ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ case V4L2_PIX_FMT_RGB565X: ++ pix->colorspace = V4L2_COLORSPACE_SRGB; ++ bpp = RGB565_BPP; ++ break; ++ case V4L2_PIX_FMT_RGB24: ++ pix->colorspace = V4L2_COLORSPACE_SRGB; ++ bpp = RGB24_BPP; ++ break; ++ case V4L2_PIX_FMT_RGB32: ++ case V4L2_PIX_FMT_BGR32: ++ pix->colorspace = V4L2_COLORSPACE_SRGB; ++ bpp = RGB32_BPP; ++ break; ++ } ++ pix->bytesperline = pix->width * bpp; ++ pix->sizeimage = pix->bytesperline * pix->height; ++ return bpp; ++} ++ ++/* ++ * omap_vout_uservirt_to_phys: This inline function is used to convert user ++ * space virtual address to physical address. ++ */ ++static inline u32 omap_vout_uservirt_to_phys(u32 virtp) ++{ ++ unsigned long physp = 0; ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ ++ vma = find_vma(mm, virtp); ++ /* For kernel direct-mapped memory, take the easy way */ ++ if (virtp >= PAGE_OFFSET) { ++ physp = virt_to_phys((void *) virtp); ++ } else if (vma && (vma->vm_flags & VM_IO) ++ && vma->vm_pgoff) { ++ /* this will catch, kernel-allocated, ++ mmaped-to-usermode addresses */ ++ physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); ++ } else { ++ /* otherwise, use get_user_pages() for general userland pages */ ++ int res, nr_pages = 1; ++ struct page *pages; ++ down_read(¤t->mm->mmap_sem); ++ ++ res = get_user_pages(current, current->mm, virtp, nr_pages, ++ 1, 0, &pages, NULL); ++ up_read(¤t->mm->mmap_sem); ++ ++ if (res == nr_pages) { ++ physp = __pa(page_address(&pages[0]) + ++ (virtp & ~PAGE_MASK)); ++ } else { ++ printk(KERN_WARNING VOUT_NAME ++ "get_user_pages failed\n"); ++ return 0; ++ } ++ } ++ ++ return physp; ++} ++ ++/* This functions 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); ++} ++ ++/* Release the VRFB context once the module exits */ ++static void omap_vout_release_vrfb(struct omap_vout_device *vout) ++{ ++ int i; ++ ++ for (i = 0; i < 4; 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); ++ } ++ ++} ++ ++/* Return true if rotation is 90 or 270 */ ++static inline int rotate_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 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; ++ } ++} ++ ++/* Free the V4L2 buffers */ ++static void omap_vout_free_buffers(struct omap_vout_device *vout) ++{ ++ int i, numbuffers; ++ ++ /* Allocate memory for the buffers */ ++ numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers; ++ vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize; ++ ++ for (i = 0; i < numbuffers; i++) { ++ omap_vout_free_buffer(vout->buf_virt_addr[i], ++ vout->buf_phy_addr[i], vout->buffer_size); ++ vout->buf_phy_addr[i] = 0; ++ vout->buf_virt_addr[i] = 0; ++ } ++} ++ ++/* Free VRFB buffers */ ++static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) ++{ ++ int j; ++ ++ for (j = 0; j < 4; j++) { ++ omap_vout_free_buffer(vout->smsshado_virt_addr[j], ++ vout->smsshado_phy_addr[j], ++ vout->smsshado_size); ++ vout->smsshado_virt_addr[j] = 0; ++ vout->smsshado_phy_addr[j] = 0; ++ } ++} ++ ++/* Allocate the buffers for the VRFB space. Data is copied from V4L2 ++ * buffers to the VRFB buffers using the DMA engine.*/ ++static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, ++ unsigned int *count, unsigned int startindex) ++{ ++ int i; ++ bool yuv_mode; ++ ++ /* Allocate the VRFB buffers only if the buffers are not ++ * allocated during init time. ++ */ ++ if ((rotation_enabled(vout)) && ++ !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; ++} ++ ++/* Convert V4L2 rotation to DSS rotation ++ * V4L2 understand 0, 90, 180, 270. ++ * convert to 0, 1, 2 and 3 repsectively for DSS */ ++static int v4l2_rot_to_dss_rot(int v4l2_rotation, enum dss_rotation *rotation, ++ bool mirror) ++{ ++ switch (v4l2_rotation) { ++ case 90: ++ *rotation = dss_rotation_90_degree; ++ return 0; ++ case 180: ++ *rotation = dss_rotation_180_degree; ++ return 0; ++ case 270: ++ *rotation = dss_rotation_270_degree; ++ return 0; ++ case 0: ++ *rotation = dss_rotation_0_degree; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++ ++} ++ ++/* 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 ++ */ ++static int omap_vout_calculate_offset(struct omap_vout_device *vout) ++{ ++ struct v4l2_pix_format *pix = &vout->pix; ++ struct v4l2_rect *crop = &vout->crop; ++ enum dss_rotation rotation; ++ bool mirroring = vout->mirror; ++ int vr_ps = 1, ps = 2, temp_ps = 2; ++ int offset = 0, ctop = 0, cleft = 0, line_length = 0; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ struct omap_dss_device *cur_display; ++ int *cropped_offset = &vout->cropped_offset; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ /* get the display device attached to the overlay */ ++ if (!ovl->manager || !ovl->manager->device) ++ return -1; ++ cur_display = ovl->manager->device; ++ ++ rotation = calc_rotation(vout); ++ ++ if (V4L2_PIX_FMT_YUYV == pix->pixelformat || ++ V4L2_PIX_FMT_UYVY == pix->pixelformat) { ++ if (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 (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; ++ } ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, ++ "%s Offset:%x\n", __func__, *cropped_offset); ++ return 0; ++} ++ ++/* convert V4L2 pixel format to DSS pixel format */ ++static enum omap_color_mode video_mode_to_dss_mode(struct omap_vout_device ++ *vout) ++{ ++ struct omap_overlay *ovl; ++ struct omapvideo_info *ovid; ++ struct v4l2_pix_format *pix = &vout->pix; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ switch (pix->pixelformat) { ++ case 0: ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ return OMAP_DSS_COLOR_YUV2; ++ ++ case V4L2_PIX_FMT_UYVY: ++ return OMAP_DSS_COLOR_UYVY; ++ ++ case V4L2_PIX_FMT_RGB565: ++ return OMAP_DSS_COLOR_RGB16; ++ ++ case V4L2_PIX_FMT_RGB24: ++ return OMAP_DSS_COLOR_RGB24P; ++ ++ case V4L2_PIX_FMT_RGB32: ++ return (ovl->id == OMAP_DSS_VIDEO1) ? ++ OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32; ++ case V4L2_PIX_FMT_BGR32: ++ return OMAP_DSS_COLOR_RGBX32; ++ ++ default: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++/* Setup the overlay */ ++int omapvid_setup_overlay(struct omap_vout_device *vout, ++ struct omap_overlay *ovl, int posx, int posy, int outw, ++ int outh, u32 addr) ++{ ++ int r = 0; ++ enum omap_color_mode mode = 0; ++ enum dss_rotation rotation; ++ bool mirror; ++ int cropheight, cropwidth, pixheight, pixwidth; ++ struct omap_overlay_info info; ++ ++ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 && ++ (outw != vout->pix.width || outh != vout->pix.height)) { ++ r = -EINVAL; ++ goto err; ++ } ++ ++ vout->dss_mode = video_mode_to_dss_mode(vout); ++ ++ if (mode == -EINVAL) { ++ r = -EINVAL; ++ goto err; ++ } ++ ++ rotation = vout->rotation; ++ mirror = vout->mirror; ++ ++ /* Setup the input plane parameters according to ++ * rotation value selected. ++ */ ++ if (rotate_90_or_270(vout)) { ++ cropheight = vout->crop.width; ++ cropwidth = vout->crop.height; ++ pixheight = vout->pix.width; ++ pixwidth = vout->pix.height; ++ } else { ++ cropheight = vout->crop.height; ++ cropwidth = vout->crop.width; ++ pixheight = vout->pix.height; ++ pixwidth = vout->pix.width; ++ } ++ ++ ovl->get_overlay_info(ovl, &info); ++ info.paddr = addr; ++ info.vaddr = NULL; ++ info.width = cropwidth; ++ info.height = cropheight; ++ info.color_mode = vout->dss_mode; ++ info.mirror = mirror; ++ info.pos_x = posx; ++ info.pos_y = posy; ++ info.out_width = outw; ++ info.out_height = outh; ++ info.global_alpha = vout->win.global_alpha; ++ if (!rotation_enabled(vout)) { ++ info.rotation = 0; ++ info.rotation_type = OMAP_DSS_ROT_DMA; ++ info.screen_width = pixwidth; ++ } else { ++ info.rotation = vout->rotation; ++ info.rotation_type = OMAP_DSS_ROT_VRFB; ++ info.screen_width = 2048; ++ } ++ ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, ++ "%s info.enable=%d info.addr=%x info.width=%d\n info.height=%d " ++ "info.color_mode=%d info.rotation=%d info.mirror=%d\n " ++ "info.posx=%d info.posy=%d info.out_width = %d info.out_height=%d\n " ++ "info.rotation_type=%d info.screen_width=%d\n", __func__, info.enabled, ++ info.paddr, info.width, info.height, info.color_mode, info.rotation, ++ info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height, ++ info.rotation_type, info.screen_width); ++ ++ r = ovl->set_overlay_info(ovl, &info); ++ if (r) ++ goto err; ++ ++ return 0; ++err: ++ printk(KERN_WARNING VOUT_NAME "setup_overlay failed\n"); ++ return r; ++} ++ ++/* Initialize the overlay structure */ ++int omapvid_init(struct omap_vout_device *vout, u32 addr) ++{ ++ int r = 0; ++ struct omapvideo_info *ovid = &vout->vid_info; ++ struct omap_overlay *ovl; ++ int posx, posy; ++ int outw, outh, temp, rotation; ++ int i; ++ struct v4l2_window *win; ++ struct omap_video_timings *timing; ++ ++ win = &vout->win; ++ rotation = vout->rotation; ++ for (i = 0; i < ovid->num_overlays; i++) { ++ ovl = ovid->overlays[i]; ++ if (!ovl->manager || !ovl->manager->device) ++ return -EINVAL; ++ ++ timing = &ovl->manager->device->panel.timings; ++ ++ outw = win->w.width; ++ outh = win->w.height; ++ switch (rotation) { ++ case dss_rotation_90_degree: ++ /* Invert the height and width for 90 ++ * and 270 degree rotation ++ */ ++ temp = outw; ++ outw = outh; ++ outh = temp; ++ posy = (timing->y_res - win->w.width)- ++ win->w.left; ++ posx = win->w.top; ++ break; ++ ++ case dss_rotation_180_degree: ++ posx = (timing->x_res - win->w.width) - ++ win->w.left; ++ posy = (timing->y_res - win->w.height) - ++ win->w.top; ++ break; ++ ++ case dss_rotation_270_degree: ++ temp = outw; ++ outw = outh; ++ outh = temp; ++ posy = win->w.left; ++ posx = (timing->x_res - win->w.height) ++ - win->w.top; ++ break; ++ ++ default: ++ posx = win->w.left; ++ posy = win->w.top; ++ break; ++ } ++ ++ r = omapvid_setup_overlay(vout, ovl, posx, posy, outw, ++ outh, addr); ++ if (r) ++ goto err; ++ } ++ return 0; ++err: ++ printk(KERN_WARNING VOUT_NAME "apply_changes failed\n"); ++ return r; ++} ++ ++/* Apply the changes set the go bit of DSS */ ++int omapvid_apply_changes(struct omap_vout_device *vout) ++{ ++ struct omapvideo_info *ovid = &vout->vid_info; ++ struct omap_overlay *ovl; ++ int i; ++ ++ for (i = 0; i < ovid->num_overlays; i++) { ++ ovl = ovid->overlays[i]; ++ if (!ovl->manager || !ovl->manager->device) ++ return -EINVAL; ++ ovl->manager->apply(ovl->manager); ++ } ++ return 0; ++ ++} ++ ++/* Video buffer call backs */ ++ ++/* Buffer setup function is called by videobuf layer when REQBUF ioctl is ++ * called. This is used to setup buffers and return size and count of ++ * buffers allocated. After the call to this buffer, videobuf layer will ++ * setup buffer queue depending on the size and count of buffers ++ */ ++static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, ++ unsigned int *size) ++{ ++ struct omap_vout_device *vout = q->priv_data; ++ int startindex = 0, i, j; ++ u32 phy_addr = 0, virt_addr = 0; ++ ++ if (!vout) ++ return -EINVAL; ++ ++ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) ++ return -EINVAL; ++ ++ startindex = (vout->vid == OMAP_VIDEO1) ? ++ video1_numbuffers : video2_numbuffers; ++ if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) ++ *count = startindex; ++ ++ if ((rotation_enabled(vout)) ++ && *count > 4) ++ *count = 4; ++ ++ /* If rotation is enabled, allocate memory for VRFB space also */ ++ if (rotation_enabled(vout)) { ++ if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) ++ return -ENOMEM; ++ } ++ ++ if (V4L2_MEMORY_MMAP != vout->memory) ++ return 0; ++ ++ /* Now allocated the V4L2 buffers */ ++ *size = vout->buffer_size; ++ startindex = (vout->vid == OMAP_VIDEO1) ? ++ video1_numbuffers : video2_numbuffers; ++ for (i = startindex; i < *count; i++) { ++ vout->buffer_size = *size; ++ ++ virt_addr = omap_vout_alloc_buffer(vout->buffer_size, ++ &phy_addr); ++ if (!virt_addr) { ++ if (!rotation_enabled(vout)) ++ break; ++ /* Free the VRFB buffers if no space for V4L2 buffers */ ++ for (j = i; j < *count; j++) { ++ omap_vout_free_buffer( ++ vout->smsshado_virt_addr[j], ++ vout->smsshado_phy_addr[j], ++ vout->smsshado_size); ++ vout->smsshado_virt_addr[j] = 0; ++ vout->smsshado_phy_addr[j] = 0; ++ } ++ } ++ vout->buf_virt_addr[i] = virt_addr; ++ vout->buf_phy_addr[i] = phy_addr; ++ } ++ *count = vout->buffer_allocated = i; ++ return 0; ++} ++ ++/* Free the V4L2 buffers additionally allocated than default ++ * number of buffers and free all the VRFB buffers */ ++static void omap_vout_free_allbuffers(struct omap_vout_device *vout) ++{ ++ int num_buffers = 0, i; ++ ++ num_buffers = (vout->vid == OMAP_VIDEO1) ? ++ video1_numbuffers : video2_numbuffers; ++ for (i = num_buffers; i < vout->buffer_allocated; i++) { ++ if (vout->buf_virt_addr[i]) { ++ omap_vout_free_buffer(vout->buf_virt_addr[i], ++ vout->buf_phy_addr[i], vout->buffer_size); ++ } ++ vout->buf_virt_addr[i] = 0; ++ vout->buf_phy_addr[i] = 0; ++ } ++ /* Free the VRFB buffers only if they are allocated ++ * during reqbufs. Don't free if init time allocated ++ */ ++ if (!vout->vrfb_static_allocation) { ++ for (i = 0; i < 4; i++) { ++ if (vout->smsshado_virt_addr[i]) { ++ omap_vout_free_buffer( ++ vout->smsshado_virt_addr[i], ++ vout->smsshado_phy_addr[i], ++ vout->smsshado_size); ++ vout->smsshado_virt_addr[i] = 0; ++ vout->smsshado_phy_addr[i] = 0; ++ } ++ } ++ } ++ vout->buffer_allocated = num_buffers; ++} ++ ++/* This function will be called when VIDIOC_QBUF ioctl is called. ++ * It prepare buffers before give out for the display. This function ++ * user space virtual address into physical address if userptr memory ++ * exchange mechanism is used. If rotation is enabled, it copies entire ++ * buffer into VRFB memory space before giving it to the DSS. ++ */ ++static int omap_vout_buffer_prepare(struct videobuf_queue *q, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ struct omap_vout_device *vout = q->priv_data; ++ 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; ++ struct videobuf_dmabuf *dmabuf = NULL; ++ enum dss_rotation rotation; ++ struct vid_vrfb_dma *tx; ++ ++ if (VIDEOBUF_NEEDS_INIT == vb->state) { ++ vb->width = vout->pix.width; ++ vb->height = vout->pix.height; ++ vb->size = vb->width * vb->height * vout->bpp; ++ vb->field = field; ++ } ++ vb->state = VIDEOBUF_PREPARED; ++ /* if user pointer memory mechanism is used, get the physical ++ * address of the buffer ++ */ ++ if (V4L2_MEMORY_USERPTR == vb->memory) { ++ if (0 == vb->baddr) ++ return -EINVAL; ++ /* Virtual address */ ++ /* priv points to struct videobuf_pci_sg_memory. But we went ++ * pointer to videobuf_dmabuf, which is member of ++ * videobuf_pci_sg_memory */ ++ dmabuf = videobuf_to_dma(q->bufs[vb->i]); ++ dmabuf->vmalloc = (void *) vb->baddr; ++ ++ /* Physical address */ ++ dmabuf->bus_addr = ++ (dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr); ++ } ++ ++ if (!rotation_enabled(vout)) { ++ dmabuf = videobuf_to_dma(q->bufs[vb->i]); ++ ++ vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr; ++ return 0; ++ } ++ dmabuf = videobuf_to_dma(q->bufs[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->bus_addr, 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; ++} ++ ++/* Buffer queue funtion will be called from the videobuf layer when _QBUF ++ * ioctl is called. It is used to enqueue buffer, which is ready to be ++ * displayed. */ ++static void omap_vout_buffer_queue(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct omap_vout_device *vout = q->priv_data; ++ ++ /* Driver is also maintainig a queue. So enqueue buffer in the driver ++ * queue */ ++ list_add_tail(&vb->queue, &vout->dma_queue); ++ ++ vb->state = VIDEOBUF_PREPARED; ++} ++ ++/* Buffer release function is called from videobuf layer to release buffer ++ * which are already allocated */ ++static void omap_vout_buffer_release(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct omap_vout_device *vout = q->priv_data; ++ ++ vb->state = VIDEOBUF_NEEDS_INIT; ++ ++ if (V4L2_MEMORY_MMAP != vout->memory) ++ return; ++} ++ ++/* ++ * File operations ++ */ ++static void omap_vout_vm_open(struct vm_area_struct *vma) ++{ ++ struct omap_vout_device *vout = vma->vm_private_data; ++ ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, ++ "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); ++ vout->mmap_count++; ++} ++ ++static void omap_vout_vm_close(struct vm_area_struct *vma) ++{ ++ struct omap_vout_device *vout = vma->vm_private_data; ++ ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, ++ "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); ++ vout->mmap_count--; ++} ++ ++static struct vm_operations_struct omap_vout_vm_ops = { ++ .open = omap_vout_vm_open, ++ .close = omap_vout_vm_close, ++}; ++ ++static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct omap_vout_device *vout = file->private_data; ++ struct videobuf_queue *q = &vout->vbq; ++ unsigned long size = (vma->vm_end - vma->vm_start); ++ unsigned long start = vma->vm_start; ++ int i; ++ void *pos; ++ struct videobuf_dmabuf *dmabuf = NULL; ++ ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, ++ " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__, ++ vma->vm_pgoff, vma->vm_start, vma->vm_end); ++ ++ /* look for the buffer to map */ ++ for (i = 0; i < VIDEO_MAX_FRAME; i++) { ++ if (NULL == q->bufs[i]) ++ continue; ++ if (V4L2_MEMORY_MMAP != q->bufs[i]->memory) ++ continue; ++ if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT)) ++ break; ++ } ++ ++ if (VIDEO_MAX_FRAME == i) { ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, ++ "offset invalid [offset=0x%lx]\n", ++ (vma->vm_pgoff << PAGE_SHIFT)); ++ return -EINVAL; ++ } ++ q->bufs[i]->baddr = vma->vm_start; ++ ++ vma->vm_flags |= VM_RESERVED; ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ vma->vm_ops = &omap_vout_vm_ops; ++ vma->vm_private_data = (void *) vout; ++ dmabuf = videobuf_to_dma(q->bufs[i]); ++ pos = dmabuf->vmalloc; ++ vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT; ++ while (size > 0) { ++ unsigned long pfn; ++ pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT; ++ if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) ++ return -EAGAIN; ++ start += PAGE_SIZE; ++ pos += PAGE_SIZE; ++ size -= PAGE_SIZE; ++ } ++ vout->mmap_count++; ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); ++ return 0; ++} ++ ++static int omap_vout_release(struct file *file) ++{ ++ ++ struct omap_vout_device *vout = file->private_data; ++ struct videobuf_queue *q; ++ unsigned int t; ++ struct omapvideo_info *ovid; ++ unsigned int r; ++ ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); ++ ovid = &vout->vid_info; ++ ++ if (!vout) ++ return 0; ++ q = &vout->vbq; ++ ++ /* Disable all the overlay managers connected with this interface */ ++ for (t = 0; t < ovid->num_overlays; t++) { ++ struct omap_overlay *ovl = ovid->overlays[t]; ++ if (ovl->manager && ovl->manager->device) { ++ struct omap_overlay_info info; ++ ovl->get_overlay_info(ovl, &info); ++ info.enabled = 0; ++ ovl->set_overlay_info(ovl, &info); ++ } ++ ++ } ++ /* Turn off the pipeline */ ++ r = omapvid_apply_changes(vout); ++ if (r) ++ printk(KERN_WARNING VOUT_NAME "Unable to apply changes\n"); ++ ++ /* Free all buffers */ ++ omap_vout_free_allbuffers(vout); ++ videobuf_mmap_free(q); ++ ++ /* Even if apply changes fails we should continue ++ freeing allocated memeory */ ++ if (vout->streaming) { ++ u32 mask = 0; ++ ++ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | ++ DISPC_IRQ_EVSYNC_ODD; ++ omap_dispc_unregister_isr(omap_vout_isr, vout, mask); ++ vout->streaming = 0; ++ ++ videobuf_streamoff(q); ++ videobuf_queue_cancel(q); ++ ++ } ++ ++ if (vout->mmap_count != 0) ++ vout->mmap_count = 0; ++ ++ vout->opened -= 1; ++ file->private_data = NULL; ++ ++ if (vout->buffer_allocated) ++ videobuf_mmap_free(q); ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); ++ return r; ++} ++ ++static int omap_vout_open(struct file *file) ++{ ++ struct omap_vout_device *vout = NULL; ++ struct videobuf_queue *q; ++ ++ vout = video_drvdata(file); ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); ++ ++ if (vout == NULL) ++ return -ENODEV; ++ ++ /* for now, we only support single open */ ++ if (vout->opened) ++ return -EBUSY; ++ ++ vout->opened += 1; ++ ++ file->private_data = vout; ++ vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ++ q = &vout->vbq; ++ video_vbq_ops.buf_setup = omap_vout_buffer_setup; ++ video_vbq_ops.buf_prepare = omap_vout_buffer_prepare; ++ video_vbq_ops.buf_release = omap_vout_buffer_release; ++ video_vbq_ops.buf_queue = omap_vout_buffer_queue; ++ spin_lock_init(&vout->vbq_lock); ++ ++ videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock, ++ vout->type, V4L2_FIELD_NONE, sizeof ++ (struct videobuf_buffer), vout); ++ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); ++ return 0; ++} ++ ++/* V4L2 ioctls */ ++static int vidioc_querycap(struct file *file, void *fh, ++ struct v4l2_capability *cap) ++{ ++ struct omap_vout_device *vout = fh; ++ ++ strlcpy(cap->driver, VOUT_NAME, ++ sizeof(cap->driver)); ++ strlcpy(cap->card, vout->vfd->name, sizeof(cap->card)); ++ cap->bus_info[0] = '\0'; ++ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; ++ return 0; ++} ++ ++static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_fmtdesc *fmt) ++{ ++ int index = fmt->index; ++ enum v4l2_buf_type type = fmt->type; ++ ++ fmt->index = index; ++ fmt->type = type; ++ if (index >= NUM_OUTPUT_FORMATS) ++ return -EINVAL; ++ ++ fmt->flags = omap_formats[index].flags; ++ strlcpy(fmt->description, omap_formats[index].description, ++ sizeof(fmt->description)); ++ fmt->pixelformat = omap_formats[index].pixelformat; ++ return 0; ++} ++ ++static int vidioc_g_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct omap_vout_device *vout = fh; ++ ++ f->fmt.pix = vout->pix; ++ return 0; ++ ++} ++ ++static int vidioc_try_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct omap_vout_device *vout = fh; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ struct omap_video_timings *timing; ++ ++ if (vout->streaming) ++ return -EBUSY; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ if (!ovl->manager || !ovl->manager->device) ++ return -EINVAL; ++ /* get the display device attached to the overlay */ ++ timing = &ovl->manager->device->panel.timings; ++ ++ vout->fbuf.fmt.height = timing->y_res; ++ vout->fbuf.fmt.width = timing->x_res; ++ ++ omap_vout_try_format(&f->fmt.pix); ++ return 0; ++} ++ ++static int vidioc_s_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct omap_vout_device *vout = fh; ++ int bpp; ++ int r; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ struct omap_video_timings *timing; ++ ++ if (vout->streaming) ++ return -EBUSY; ++ ++ mutex_lock(&vout->lock); ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ /* get the display device attached to the overlay */ ++ if (!ovl->manager || !ovl->manager->device) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ timing = &ovl->manager->device->panel.timings; ++ ++ /* We dont support RGB24-packed mode if vrfb rotation ++ * is enabled*/ ++ if ((rotation_enabled(vout)) && ++ f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ ++ /* get the framebuffer parameters */ ++ ++ if (rotate_90_or_270(vout)) { ++ vout->fbuf.fmt.height = timing->x_res; ++ vout->fbuf.fmt.width = timing->y_res; ++ } else { ++ vout->fbuf.fmt.height = timing->y_res; ++ vout->fbuf.fmt.width = timing->x_res; ++ } ++ ++ /* change to samller size is OK */ ++ ++ bpp = omap_vout_try_format(&f->fmt.pix); ++ f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp; ++ ++ /* try & set the new output format */ ++ vout->bpp = bpp; ++ vout->pix = f->fmt.pix; ++ vout->vrfb_bpp = 1; ++ ++ /* If YUYV then vrfb bpp is 2, for others its 1 */ ++ if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat || ++ V4L2_PIX_FMT_UYVY == vout->pix.pixelformat) ++ vout->vrfb_bpp = 2; ++ ++ /* set default crop and win */ ++ omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win); ++ ++ /* Save the changes in the overlay strcuture */ ++ r = omapvid_init(vout, 0); ++ if (r) { ++ printk(KERN_ERR VOUT_NAME "failed to change mode\n"); ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ mutex_unlock(&vout->lock); ++ return 0; ++} ++ ++static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ int err = -EINVAL; ++ struct omap_vout_device *vout = fh; ++ struct v4l2_window *win = &f->fmt.win; ++ ++ err = omap_vout_try_window(&vout->fbuf, win); ++ ++ if (err) ++ return err; ++ ++ if (vout->vid == OMAP_VIDEO1) ++ win->global_alpha = 255; ++ else ++ win->global_alpha = f->fmt.win.global_alpha; ++ ++ return 0; ++} ++ ++static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct omap_vout_device *vout = fh; ++ int err = -EINVAL; ++ struct omap_overlay *ovl; ++ struct omapvideo_info *ovid; ++ struct v4l2_window *win = &f->fmt.win; ++ ++ mutex_lock(&vout->lock); ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ err = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); ++ if (err) { ++ mutex_unlock(&vout->lock); ++ return err; ++ } ++ /* Video1 plane does not support global alpha */ ++ if (ovl->id == OMAP_DSS_VIDEO1) ++ vout->win.global_alpha = 255; ++ else ++ vout->win.global_alpha = f->fmt.win.global_alpha; ++ ++ vout->win.chromakey = f->fmt.win.chromakey; ++ mutex_unlock(&vout->lock); ++ return 0; ++} ++ ++static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, ++ struct v4l2_fmtdesc *fmt) ++{ ++ int index = fmt->index; ++ enum v4l2_buf_type type = fmt->type; ++ ++ fmt->index = index; ++ fmt->type = type; ++ if (index >= NUM_OUTPUT_FORMATS) ++ return -EINVAL; ++ ++ fmt->flags = omap_formats[index].flags; ++ strlcpy(fmt->description, omap_formats[index].description, ++ sizeof(fmt->description)); ++ fmt->pixelformat = omap_formats[index].pixelformat; ++ return 0; ++} ++ ++static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct omap_vout_device *vout = fh; ++ struct omap_overlay *ovl; ++ struct omapvideo_info *ovid; ++ struct omap_overlay_manager_info info; ++ struct v4l2_window *win = &f->fmt.win; ++ u32 key_value = 0; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ win->w = vout->win.w; ++ win->field = vout->win.field; ++ win->global_alpha = vout->win.global_alpha; ++ ++ if (ovl->manager && ovl->manager->get_manager_info) { ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ key_value = info.trans_key; ++ } ++ win->chromakey = key_value; ++ return 0; ++} ++ ++static int vidioc_cropcap(struct file *file, void *fh, ++ struct v4l2_cropcap *cropcap) ++{ ++ struct omap_vout_device *vout = fh; ++ enum v4l2_buf_type type = cropcap->type; ++ struct v4l2_pix_format *pix = &vout->pix; ++ ++ cropcap->type = type; ++ if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ /* Width and height are always even */ ++ cropcap->bounds.width = pix->width & ~1; ++ cropcap->bounds.height = pix->height & ~1; ++ ++ omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect); ++ cropcap->pixelaspect.numerator = 1; ++ cropcap->pixelaspect.denominator = 1; ++ return 0; ++} ++ ++static int vidioc_g_crop(struct file *file, void *fh, ++ struct v4l2_crop *crop) ++{ ++ struct omap_vout_device *vout = fh; ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ crop->c = vout->crop; ++ return 0; ++} ++ ++static int vidioc_s_crop(struct file *file, void *fh, ++ struct v4l2_crop *crop) ++{ ++ struct omap_vout_device *vout = fh; ++ int err = -EINVAL; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ struct omap_video_timings *timing; ++ ++ if (vout->streaming) ++ return -EBUSY; ++ ++ mutex_lock(&vout->lock); ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ if (!ovl->manager || !ovl->manager->device) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ /* get the display device attached to the overlay */ ++ timing = &ovl->manager->device->panel.timings; ++ ++ if (rotate_90_or_270(vout)) { ++ vout->fbuf.fmt.height = timing->x_res; ++ vout->fbuf.fmt.width = timing->y_res; ++ } else { ++ vout->fbuf.fmt.height = timing->y_res; ++ vout->fbuf.fmt.width = timing->x_res; ++ } ++ ++ if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ++ err = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win, ++ &vout->fbuf, &crop->c); ++ mutex_unlock(&vout->lock); ++ return err; ++ } else { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++} ++ ++static int vidioc_queryctrl(struct file *file, void *fh, ++ struct v4l2_queryctrl *ctrl) ++{ ++ switch (ctrl->id) { ++ case V4L2_CID_ROTATE: ++ v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0); ++ break; ++ case V4L2_CID_BG_COLOR: ++ v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0); ++ break; ++ case V4L2_CID_VFLIP: ++ v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); ++ default: ++ ctrl->name[0] = '\0'; ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) ++{ ++ struct omap_vout_device *vout = fh; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ROTATE: ++ ctrl->value = vout->control[0].value; ++ return 0; ++ case V4L2_CID_BG_COLOR: ++ { ++ struct omap_overlay_manager_info info; ++ struct omap_overlay *ovl; ++ ovl = vout->vid_info.overlays[0]; ++ ++ if (!ovl->manager || !ovl->manager->get_manager_info) ++ return -EINVAL; ++ ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ ctrl->value = info.default_color; ++ return 0; ++ } ++ ++ case V4L2_CID_VFLIP: ++ ctrl->value = vout->control[2].value; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct omap_vout_device *vout = fh; ++ ++ switch (a->id) { ++ case V4L2_CID_ROTATE: ++ { ++ int rotation = a->value; ++ ++ mutex_lock(&vout->lock); ++ ++ if (rotation && ++ vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ ++ if ((v4l2_rot_to_dss_rot(rotation, &vout->rotation, ++ vout->mirror))) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ ++ vout->control[0].value = rotation; ++ mutex_unlock(&vout->lock); ++ return 0; ++ } ++ case V4L2_CID_BG_COLOR: ++ { ++ unsigned int color = a->value; ++ struct omap_overlay_manager_info info; ++ struct omap_overlay *ovl; ++ ovl = vout->vid_info.overlays[0]; ++ ++ mutex_lock(&vout->lock); ++ if (!ovl->manager || !ovl->manager->get_manager_info) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ info.default_color = color; ++ if (ovl->manager->set_manager_info(ovl->manager, &info)) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ ++ vout->control[1].value = color; ++ mutex_unlock(&vout->lock); ++ return 0; ++ } ++ case V4L2_CID_VFLIP: ++ { ++ unsigned int mirror = a->value; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ mutex_lock(&vout->lock); ++ ++ if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ vout->mirror = mirror; ++ vout->control[2].value = mirror; ++ mutex_unlock(&vout->lock); ++ return 0; ++ } ++ ++ default: ++ return -EINVAL; ++ } ++ ++} ++ ++static int vidioc_reqbufs(struct file *file, void *fh, ++ struct v4l2_requestbuffers *req) ++{ ++ struct omap_vout_device *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ unsigned int i, num_buffers = 0; ++ int ret = 0; ++ struct videobuf_dmabuf *dmabuf = NULL; ++ ++ if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) ++ return -EINVAL; ++ /* if memory is not mmp or userptr ++ return error */ ++ if ((V4L2_MEMORY_MMAP != req->memory) && ++ (V4L2_MEMORY_USERPTR != req->memory)) ++ return -EINVAL; ++ ++ mutex_lock(&vout->lock); ++ /* Cannot be requested when streaming is on */ ++ if (vout->streaming) { ++ mutex_unlock(&vout->lock); ++ return -EBUSY; ++ } ++ ++ /* If buffers are already allocated free them */ ++ if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) { ++ if (vout->mmap_count) { ++ mutex_unlock(&vout->lock); ++ return -EBUSY; ++ } ++ num_buffers = (vout->vid == OMAP_VIDEO1) ? ++ video1_numbuffers : video2_numbuffers; ++ for (i = num_buffers; i < vout->buffer_allocated; i++) { ++ dmabuf = videobuf_to_dma(q->bufs[i]); ++ omap_vout_free_buffer((u32)dmabuf->vmalloc, ++ dmabuf->bus_addr, vout->buffer_size); ++ vout->buf_virt_addr[i] = 0; ++ vout->buf_phy_addr[i] = 0; ++ } ++ vout->buffer_allocated = num_buffers; ++ videobuf_mmap_free(q); ++ } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) { ++ if (vout->buffer_allocated) { ++ videobuf_mmap_free(q); ++ for (i = 0; i < vout->buffer_allocated; i++) { ++ kfree(q->bufs[i]); ++ q->bufs[i] = NULL; ++ } ++ vout->buffer_allocated = 0; ++ } ++ } ++ ++ /*store the memory type in data structure */ ++ vout->memory = req->memory; ++ ++ INIT_LIST_HEAD(&vout->dma_queue); ++ ++ /* call videobuf_reqbufs api */ ++ ret = videobuf_reqbufs(q, req); ++ if (ret < 0) { ++ mutex_unlock(&vout->lock); ++ return ret; ++ } ++ ++ vout->buffer_allocated = req->count; ++ for (i = 0; i < req->count; i++) { ++ dmabuf = videobuf_to_dma(q->bufs[i]); ++ dmabuf->vmalloc = (void *) vout->buf_virt_addr[i]; ++ dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i]; ++ dmabuf->sglen = 1; ++ } ++ mutex_unlock(&vout->lock); ++ return 0; ++} ++ ++static int vidioc_querybuf(struct file *file, void *fh, ++ struct v4l2_buffer *b) ++{ ++ struct omap_vout_device *vout = fh; ++ ++ return videobuf_querybuf(&vout->vbq, b); ++} ++ ++static int vidioc_qbuf(struct file *file, void *fh, ++ struct v4l2_buffer *buffer) ++{ ++ struct omap_vout_device *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ int ret = 0; ++ ++ if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) || ++ (buffer->index >= vout->buffer_allocated) || ++ (q->bufs[buffer->index]->memory != buffer->memory)) { ++ return -EINVAL; ++ } ++ if (V4L2_MEMORY_USERPTR == buffer->memory) { ++ if ((buffer->length < vout->pix.sizeimage) || ++ (0 == buffer->m.userptr)) { ++ return -EINVAL; ++ } ++ } ++ ++ if ((rotation_enabled(vout)) && ++ vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) { ++ printk(KERN_WARNING VOUT_NAME ++ "DMA Channel not allocated for Rotation\n"); ++ return -EINVAL; ++ } ++ ++ ret = videobuf_qbuf(q, buffer); ++ return ret; ++} ++ ++static int vidioc_dqbuf(struct file *file, void *fh, ++ struct v4l2_buffer *b) ++{ ++ struct omap_vout_device *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ int ret = 0; ++ ++ if (!vout->streaming) ++ return -EINVAL; ++ ++ if (file->f_flags & O_NONBLOCK) ++ /* Call videobuf_dqbuf for non blocking mode */ ++ ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1); ++ else ++ /* Call videobuf_dqbuf for blocking mode */ ++ ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0); ++ return ret; ++} ++ ++static int vidioc_streamon(struct file *file, void *fh, ++ enum v4l2_buf_type i) ++{ ++ struct omap_vout_device *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ u32 addr = 0; ++ int r = 0; ++ int t; ++ struct omapvideo_info *ovid = &vout->vid_info; ++ u32 mask = 0; ++ ++ mutex_lock(&vout->lock); ++ ++ if (vout->streaming) { ++ mutex_unlock(&vout->lock); ++ return -EBUSY; ++ } ++ ++ r = videobuf_streamon(q); ++ if (r < 0) { ++ mutex_unlock(&vout->lock); ++ return r; ++ } ++ ++ if (list_empty(&vout->dma_queue)) { ++ mutex_unlock(&vout->lock); ++ return -EIO; ++ } ++ /* Get the next frame from the buffer queue */ ++ vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next, ++ struct videobuf_buffer, queue); ++ /* Remove buffer from the buffer queue */ ++ list_del(&vout->cur_frm->queue); ++ /* Mark state of the current frame to active */ ++ vout->cur_frm->state = VIDEOBUF_ACTIVE; ++ /* Initialize field_id and started member */ ++ vout->field_id = 0; ++ ++ /* set flag here. Next QBUF will start DMA */ ++ vout->streaming = 1; ++ ++ vout->first_int = 1; ++ ++ if (omap_vout_calculate_offset(vout)) { ++ mutex_unlock(&vout->lock); ++ return -EINVAL; ++ } ++ addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i] ++ + vout->cropped_offset; ++ ++ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | ++ DISPC_IRQ_EVSYNC_ODD; ++ ++ omap_dispc_register_isr(omap_vout_isr, vout, mask); ++ ++ for (t = 0; t < ovid->num_overlays; t++) { ++ struct omap_overlay *ovl = ovid->overlays[t]; ++ if (ovl->manager && ovl->manager->device) { ++ struct omap_overlay_info info; ++ ovl->get_overlay_info(ovl, &info); ++ info.enabled = 1; ++ info.paddr = addr; ++ if (ovl->set_overlay_info(ovl, &info)) ++ return -EINVAL; ++ } ++ } ++ ++ /* First save the configuration in ovelray structure */ ++ r = omapvid_init(vout, addr); ++ if (r) ++ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n"); ++ /* Enable the pipeline and set the Go bit */ ++ r = omapvid_apply_changes(vout); ++ if (r) ++ printk(KERN_ERR VOUT_NAME "failed to change mode\n"); ++ ++ mutex_unlock(&vout->lock); ++ return r; ++} ++ ++static int vidioc_streamoff(struct file *file, void *fh, ++ enum v4l2_buf_type i) ++{ ++ struct omap_vout_device *vout = fh; ++ int t, r = 0; ++ struct omapvideo_info *ovid = &vout->vid_info; ++ u32 mask = 0; ++ ++ if (!vout->streaming) ++ return -EINVAL; ++ ++ vout->streaming = 0; ++ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | ++ DISPC_IRQ_EVSYNC_ODD; ++ ++ omap_dispc_unregister_isr(omap_vout_isr, vout, mask); ++ ++ for (t = 0; t < ovid->num_overlays; t++) { ++ struct omap_overlay *ovl = ovid->overlays[t]; ++ if (ovl->manager && ovl->manager->device) { ++ struct omap_overlay_info info; ++ ++ ovl->get_overlay_info(ovl, &info); ++ info.enabled = 0; ++ return ovl->set_overlay_info(ovl, &info); ++ } ++ } ++ ++ /* Turn of the pipeline */ ++ r = omapvid_apply_changes(vout); ++ if (r) { ++ printk(KERN_ERR VOUT_NAME "failed to change mode\n"); ++ return r; ++ } ++ videobuf_streamoff(&vout->vbq); ++ videobuf_queue_cancel(&vout->vbq); ++ return 0; ++} ++ ++static int vidioc_s_fbuf(struct file *file, void *fh, ++ struct v4l2_framebuffer *a) ++{ ++ struct omap_vout_device *vout = fh; ++ struct omap_overlay_manager_info info; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST; ++ int enable = 0; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ /* OMAP DSS doesn't support Source and Destination color ++ key together */ ++ if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && ++ (a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) ++ return -EINVAL; ++ /* OMAP DSS Doesn't support the Destination color key ++ and alpha blending together */ ++ if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) && ++ (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) ++ return -EINVAL; ++ ++ if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) { ++ vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; ++ key_type = OMAP_DSS_COLOR_KEY_VID_SRC; ++ } else ++ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY; ++ ++ if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) { ++ vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY; ++ key_type = OMAP_DSS_COLOR_KEY_GFX_DST; ++ } else ++ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY; ++ ++ if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY | ++ V4L2_FBUF_FLAG_SRC_CHROMAKEY)) ++ enable = 1; ++ else ++ enable = 0; ++ if (ovl->manager && ovl->manager->get_manager_info && ++ ovl->manager->set_manager_info) { ++ ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ info.trans_enabled = enable; ++ info.trans_key_type = key_type; ++ info.trans_key = vout->win.chromakey; ++ ++ if (ovl->manager->set_manager_info(ovl->manager, &info)) ++ return -EINVAL; ++ } ++ if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) { ++ vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; ++ enable = 1; ++ } else { ++ vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA; ++ enable = 0; ++ } ++ if (ovl->manager && ovl->manager->get_manager_info && ++ ovl->manager->set_manager_info) { ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ info.alpha_enabled = enable; ++ if (ovl->manager->set_manager_info(ovl->manager, &info)) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vidioc_g_fbuf(struct file *file, void *fh, ++ struct v4l2_framebuffer *a) ++{ ++ struct omap_vout_device *vout = fh; ++ struct omap_overlay_manager_info info; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ ++ a->flags = 0x0; ++ ++ a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY ++ | V4L2_FBUF_CAP_SRC_CHROMAKEY; ++ ++ if (ovl->manager && ovl->manager->get_manager_info) { ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC) ++ a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; ++ if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST) ++ a->flags |= V4L2_FBUF_FLAG_CHROMAKEY; ++ } ++ if (ovl->manager && ovl->manager->get_manager_info) { ++ ovl->manager->get_manager_info(ovl->manager, &info); ++ if (info.alpha_enabled) ++ a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops vout_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, ++ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, ++ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, ++ .vidioc_queryctrl = vidioc_queryctrl, ++ .vidioc_g_ctrl = vidioc_g_ctrl, ++ .vidioc_s_fbuf = vidioc_s_fbuf, ++ .vidioc_g_fbuf = vidioc_g_fbuf, ++ .vidioc_s_ctrl = vidioc_s_ctrl, ++ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, ++ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, ++ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, ++ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, ++ .vidioc_cropcap = vidioc_cropcap, ++ .vidioc_g_crop = vidioc_g_crop, ++ .vidioc_s_crop = vidioc_s_crop, ++ .vidioc_reqbufs = vidioc_reqbufs, ++ .vidioc_querybuf = vidioc_querybuf, ++ .vidioc_qbuf = vidioc_qbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++}; ++ ++static const struct v4l2_file_operations omap_vout_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = video_ioctl2, ++ .mmap = omap_vout_mmap, ++ .open = omap_vout_open, ++ .release = omap_vout_release, ++}; ++ ++/* Init functions used during driver intitalization */ ++/* Initial setup of video_data */ ++static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) ++{ ++ struct v4l2_pix_format *pix; ++ struct video_device *vfd; ++ struct v4l2_control *control; ++ struct omap_dss_device *display = ++ vout->vid_info.overlays[0]->manager->device; ++ ++ /* set the default pix */ ++ pix = &vout->pix; ++ ++ /* Set the default picture of QVGA */ ++ pix->width = QQVGA_WIDTH; ++ pix->height = QQVGA_HEIGHT; ++ ++ /* Default pixel format is RGB 5-6-5 */ ++ pix->pixelformat = V4L2_PIX_FMT_RGB565; ++ pix->field = V4L2_FIELD_ANY; ++ pix->bytesperline = pix->width * 2; ++ pix->sizeimage = pix->bytesperline * pix->height; ++ pix->priv = 0; ++ pix->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ vout->bpp = RGB565_BPP; ++ vout->fbuf.fmt.width = display->panel.timings.x_res; ++ vout->fbuf.fmt.height = display->panel.timings.y_res; ++ ++ /* Set the data structures for the overlay parameters*/ ++ vout->win.global_alpha = 255; ++ vout->fbuf.flags = 0; ++ vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA | ++ V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY; ++ vout->win.chromakey = 0; ++ ++ omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win); ++ ++ /*Initialize the control variables for ++ rotation, flipping and background color. */ ++ control = vout->control; ++ control[0].id = V4L2_CID_ROTATE; ++ control[0].value = 0; ++ vout->rotation = 0; ++ vout->mirror = 0; ++ vout->control[2].id = V4L2_CID_HFLIP; ++ vout->control[2].value = 0; ++ vout->vrfb_bpp = 2; ++ ++ control[1].id = V4L2_CID_BG_COLOR; ++ control[1].value = 0; ++ ++ /* initialize the video_device struct */ ++ vfd = vout->vfd = video_device_alloc(); ++ ++ if (!vfd) { ++ printk(KERN_ERR VOUT_NAME ": could not allocate" ++ " video device struct\n"); ++ return -ENOMEM; ++ } ++ vfd->release = video_device_release; ++ vfd->ioctl_ops = &vout_ioctl_ops; ++ ++ strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name)); ++ vfd->vfl_type = VFL_TYPE_GRABBER; ++ ++ /* need to register for a VID_HARDWARE_* ID in videodev.h */ ++ vfd->fops = &omap_vout_fops; ++ mutex_init(&vout->lock); ++ ++ vfd->minor = -1; ++ return 0; ++ ++} ++ ++/* Setup video buffers */ ++static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, ++ int vid_num) ++{ ++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); ++ struct omap2video_device *vid_dev = container_of(v4l2_dev, struct ++ omap2video_device, v4l2_dev); ++ struct omap_vout_device *vout; ++ int i, j, r = 0; ++ int image_width, image_height; ++ unsigned numbuffers; ++ struct video_device *vfd; ++ int static_vrfb_allocation = 0, vrfb_num_bufs = 4; ++ ++ vout = vid_dev->vouts[vid_num]; ++ vfd = vout->vfd; ++ ++ numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; ++ vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; ++ printk(KERN_INFO VOUT_NAME "Buffer Size = %d\n", vout->buffer_size); ++ for (i = 0; i < numbuffers; i++) { ++ vout->buf_virt_addr[i] = ++ omap_vout_alloc_buffer(vout->buffer_size, ++ (u32 *) &vout->buf_phy_addr[i]); ++ if (!vout->buf_virt_addr[i]) { ++ numbuffers = i; ++ r = -ENOMEM; ++ goto free_buffers; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) { ++ if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { ++ printk(KERN_INFO VOUT_NAME ": VRFB Region allocation " ++ "for rotation failed\n"); ++ r = -ENOMEM; ++ break; ++ } ++ } ++ if (r == -ENOMEM) { ++ for (j = 0; j < i; j++) ++ omap_vrfb_release_ctx(&vout->vrfb_context[j]); ++ ++ goto free_buffers; ++ } ++ ++ vout->cropped_offset = 0; ++ ++ /* 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; ++ r = 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 (r < 0) { ++ vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; ++ printk(KERN_INFO VOUT_NAME ": DMA Channel not alloted " ++ "for video%d [v4l2]\n", vfd->minor); ++ } ++ init_waitqueue_head(&vout->vrfb_dma_tx.wait); ++ ++ /* Allocate VRFB buffers if selected through bootargs */ ++ static_vrfb_allocation = (vid_num == 0) ? ++ vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; ++ ++ /* 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)) { ++ r = -ENOMEM; ++ goto free_buffers; ++ } ++ vout->vrfb_static_allocation = 1; ++ } ++ return 0; ++ ++free_buffers: ++ for (i = 0; i < numbuffers; i++) { ++ omap_vout_free_buffer(vout->buf_virt_addr[i], ++ vout->buf_phy_addr[i], vout->buffer_size); ++ vout->buf_virt_addr[i] = 0; ++ vout->buf_phy_addr[i] = 0; ++ } ++ return r; ++ ++} ++ ++/* Create video out devices */ ++static int __init omap_vout_create_video_devices(struct platform_device *pdev) ++{ ++ int r = 0, k; ++ struct omap_vout_device *vout; ++ struct video_device *vfd = NULL; ++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); ++ ++ struct omap2video_device *vid_dev = container_of(v4l2_dev, struct ++ omap2video_device, v4l2_dev); ++ ++ for (k = 0; k < pdev->num_resources; k++) { ++ ++ vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL); ++ if (!vout) { ++ printk(KERN_ERR VOUT_NAME ++ ": could not allocate memory\n"); ++ return -ENOMEM; ++ } ++ ++ memset(vout, 0, sizeof(struct omap_vout_device)); ++ ++ vout->vid = k; ++ vid_dev->vouts[k] = vout; ++ vout->vid_dev = vid_dev; ++ /* Select video2 if only 1 overlay is controlled by V4L2 */ ++ if (pdev->num_resources == 1) ++ vout->vid_info.overlays[0] = vid_dev->overlays[k + 2]; ++ else ++ /* Else select video1 and video2 one by one. */ ++ vout->vid_info.overlays[0] = vid_dev->overlays[k + 1]; ++ vout->vid_info.num_overlays = 1; ++ vout->vid_info.id = k + 1; ++ vid_dev->num_videos++; ++ ++ /* Setup the default configuration for the video devices ++ */ ++ if (omap_vout_setup_video_data(vout) != 0) { ++ r = -ENOMEM; ++ goto error; ++ } ++ ++ /* Allocate default number of buffers for the video streaming ++ * and reserve the VRFB space for rotation ++ */ ++ if (omap_vout_setup_video_bufs(pdev, k) != 0) { ++ r = -ENOMEM; ++ goto error1; ++ } ++ ++ /* Register the Video device with V4L2 ++ */ ++ vfd = vout->vfd; ++ if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) { ++ printk(KERN_ERR VOUT_NAME ": could not register " ++ "Video for Linux device\n"); ++ vfd->minor = -1; ++ r = -ENODEV; ++ goto error2; ++ } ++ video_set_drvdata(vfd, vout); ++ ++ /* Configure the overlay structure */ ++ r = omapvid_init(vid_dev->vouts[k], 0); ++ ++ if (r) ++ goto error2; ++ else ++ goto success; ++error2: ++ omap_vout_release_vrfb(vout); ++ omap_vout_free_buffers(vout); ++error1: ++ video_device_release(vfd); ++error: ++ kfree(vout); ++ return r; ++ ++success: ++ printk(KERN_INFO VOUT_NAME ": registered and initialized " ++ "video device %d [v4l2]\n", vfd->minor); ++ if (k == (pdev->num_resources - 1)) ++ return 0; ++ } ++ return -ENODEV; ++ ++} ++/* Driver functions */ ++static int omap_vout_remove(struct platform_device *pdev) ++{ ++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); ++ struct omap2video_device *vid_dev = container_of(v4l2_dev, struct ++ omap2video_device, v4l2_dev); ++ int k; ++ ++ v4l2_device_unregister(v4l2_dev); ++ for (k = 0; k < pdev->num_resources; k++) ++ omap_vout_cleanup_device(vid_dev->vouts[k]); ++ ++ for (k = 0; k < vid_dev->num_displays; k++) { ++ if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED) ++ vid_dev->displays[k]->disable(vid_dev->displays[k]); ++ ++ omap_dss_put_device(vid_dev->displays[k]); ++ } ++ kfree(vid_dev); ++ return 0; ++} ++ ++static int __init omap_vout_probe(struct platform_device *pdev) ++{ ++ int r = 0, i; ++ struct omap2video_device *vid_dev = NULL; ++ struct omap_overlay *ovl; ++ struct omap_dss_device *def_display; ++ struct omap_dss_device *dssdev; ++ ++ if (pdev->num_resources == 0) { ++ dev_err(&pdev->dev, "probed for an unknown device\n"); ++ r = -ENODEV; ++ return r; ++ } ++ ++ vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL); ++ if (vid_dev == NULL) { ++ r = -ENOMEM; ++ return r; ++ } ++ ++ vid_dev->num_displays = 0; ++ dssdev = NULL; ++ for_each_dss_dev(dssdev) { ++ omap_dss_get_device(dssdev); ++ vid_dev->displays[vid_dev->num_displays++] = dssdev; ++ } ++ ++ if (vid_dev->num_displays == 0) { ++ dev_err(&pdev->dev, "no displays\n"); ++ r = -EINVAL; ++ goto error0; ++ } ++ ++ vid_dev->num_overlays = omap_dss_get_num_overlays(); ++ for (i = 0; i < vid_dev->num_overlays; i++) ++ vid_dev->overlays[i] = omap_dss_get_overlay(i); ++ ++ vid_dev->num_managers = omap_dss_get_num_overlay_managers(); ++ for (i = 0; i < vid_dev->num_managers; i++) ++ vid_dev->managers[i] = omap_dss_get_overlay_manager(i); ++ ++ /* Get the Video1 overlay and video2 overlay. ++ * Setup the Display attached to that overlays ++ */ ++ for (i = 1; i < 3; i++) { ++ ovl = omap_dss_get_overlay(i); ++ if (ovl->manager && ovl->manager->device) { ++ def_display = ovl->manager->device; ++ } else { ++ dev_warn(&pdev->dev, "cannot find display\n"); ++ def_display = NULL; ++ } ++ if (def_display) { ++ r = def_display->enable(def_display); ++ if (r) { ++ /* Here we are not considering a error ++ * as display may be enabled by frame ++ * buffer driver ++ */ ++ dev_warn(&pdev->dev, ++ "'%s' Display already enabled\n", ++ def_display->name); ++ } ++ /* set the update mode */ ++ if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { ++#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE ++ if (def_display->enable_te) ++ def_display->enable_te(def_display, 1); ++ if (def_display->set_update_mode) ++ def_display->set_update_mode(def_display, ++ OMAP_DSS_UPDATE_AUTO); ++#else /* MANUAL_UPDATE */ ++ if (def_display->enable_te) ++ def_display->enable_te(def_display, 0); ++ if (def_display->set_update_mode) ++ def_display->set_update_mode(def_display, ++ OMAP_DSS_UPDATE_MANUAL); ++#endif ++ } else { ++ if (def_display->set_update_mode) ++ def_display->set_update_mode(def_display, ++ OMAP_DSS_UPDATE_AUTO); ++ } ++ } ++ } ++ ++ if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) { ++ printk(KERN_ERR VOUT_NAME "v4l2_device_register failed\n"); ++ return -ENODEV; ++ } ++ ++ r = omap_vout_create_video_devices(pdev); ++ if (r) ++ goto error0; ++ ++ for (i = 0; i < vid_dev->num_displays; i++) { ++ struct omap_dss_device *display = vid_dev->displays[i]; ++ ++ if (display->update) ++ display->update(display, 0, 0, ++ display->panel.timings.x_res, ++ display->panel.timings.y_res); ++ } ++ return 0; ++ ++error0: ++ kfree(vid_dev); ++ return r; ++} ++ ++static struct platform_driver omap_vout_driver = { ++ .driver = { ++ .name = VOUT_NAME, ++ }, ++ .probe = omap_vout_probe, ++ .remove = omap_vout_remove, ++}; ++ ++void omap_vout_isr(void *arg, unsigned int irqstatus) ++{ ++ int r; ++ struct timeval timevalue; ++ struct omap_vout_device *vout = ++ (struct omap_vout_device *) arg; ++ u32 addr, fid; ++ struct omapvideo_info *ovid; ++ struct omap_overlay *ovl; ++ struct omap_dss_device *cur_display; ++ ++ if (!vout->streaming) ++ return; ++ ++ ovid = &vout->vid_info; ++ ovl = ovid->overlays[0]; ++ /* get the display device attached to the overlay */ ++ if (!ovl->manager || !ovl->manager->device) ++ return; ++ cur_display = ovl->manager->device; ++ ++ spin_lock(&vout->vbq_lock); ++ do_gettimeofday(&timevalue); ++ if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) { ++ if (!(irqstatus & DISPC_IRQ_VSYNC)) ++ return; ++ if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { ++ vout->cur_frm->ts = timevalue; ++ vout->cur_frm->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&vout->cur_frm->done); ++ vout->cur_frm = vout->next_frm; ++ } ++ vout->first_int = 0; ++ if (list_empty(&vout->dma_queue)) { ++ spin_unlock(&vout->vbq_lock); ++ return; ++ } ++ ++ vout->next_frm = list_entry(vout->dma_queue.next, ++ struct videobuf_buffer, queue); ++ list_del(&vout->next_frm->queue); ++ ++ vout->next_frm->state = VIDEOBUF_ACTIVE; ++ ++ addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] ++ + vout->cropped_offset; ++ ++ /* First save the configuration in ovelray structure */ ++ r = omapvid_init(vout, addr); ++ if (r) ++ printk(KERN_ERR VOUT_NAME "failed to set overlay info\n"); ++ /* Enable the pipeline and set the Go bit */ ++ r = omapvid_apply_changes(vout); ++ if (r) ++ printk(KERN_ERR VOUT_NAME "failed to change mode\n"); ++ } else { ++ ++ if (vout->first_int) { ++ vout->first_int = 0; ++ spin_unlock(&vout->vbq_lock); ++ return; ++ } ++ if (irqstatus & DISPC_IRQ_EVSYNC_ODD) { ++ fid = 1; ++ } else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) { ++ fid = 0; ++ } else { ++ spin_unlock(&vout->vbq_lock); ++ return; ++ } ++ vout->field_id ^= 1; ++ if (fid != vout->field_id) { ++ if (0 == fid) ++ vout->field_id = fid; ++ ++ spin_unlock(&vout->vbq_lock); ++ return; ++ } ++ if (0 == fid) { ++ if (vout->cur_frm == vout->next_frm) { ++ spin_unlock(&vout->vbq_lock); ++ return; ++ } ++ vout->cur_frm->ts = timevalue; ++ vout->cur_frm->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&vout->cur_frm->done); ++ vout->cur_frm = vout->next_frm; ++ } else if (1 == fid) { ++ if (list_empty(&vout->dma_queue) || ++ (vout->cur_frm != vout->next_frm)) { ++ spin_unlock(&vout->vbq_lock); ++ return; ++ } ++ vout->next_frm = list_entry(vout->dma_queue.next, ++ struct videobuf_buffer, queue); ++ list_del(&vout->next_frm->queue); ++ ++ vout->next_frm->state = VIDEOBUF_ACTIVE; ++ addr = (unsigned long) ++ vout->queued_buf_addr[vout->next_frm->i] + ++ vout->cropped_offset; ++ /* First save the configuration in ovelray structure */ ++ r = omapvid_init(vout, addr); ++ if (r) ++ printk(KERN_ERR VOUT_NAME ++ "failed to set overlay info\n"); ++ /* Enable the pipeline and set the Go bit */ ++ r = omapvid_apply_changes(vout); ++ if (r) ++ printk(KERN_ERR VOUT_NAME ++ "failed to change mode\n"); ++ } ++ ++ } ++ spin_unlock(&vout->vbq_lock); ++} ++ ++static void omap_vout_cleanup_device(struct omap_vout_device *vout) ++{ ++ struct video_device *vfd; ++ ++ if (!vout) ++ return; ++ vfd = vout->vfd; ++ ++ if (vfd) { ++ if (vfd->minor == -1) { ++ /* ++ * The device was never registered, so release the ++ * video_device struct directly. ++ */ ++ video_device_release(vfd); ++ } else { ++ /* ++ * The unregister function will release the video_device ++ * struct as well as unregistering it. ++ */ ++ video_unregister_device(vfd); ++ } ++ } ++ ++ omap_vout_release_vrfb(vout); ++ ++ omap_vout_free_buffers(vout); ++ /* Free the VRFB buffer if allocated ++ * init time ++ */ ++ if (vout->vrfb_static_allocation) ++ omap_vout_free_vrfb_buffers(vout); ++ ++ kfree(vout); ++} ++ ++static int __init omap_vout_init(void) ++{ ++ ++ if (platform_driver_register(&omap_vout_driver) != 0) { ++ printk(KERN_ERR VOUT_NAME ": could not register \ ++ Video driver\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static void omap_vout_cleanup(void) ++{ ++ platform_driver_unregister(&omap_vout_driver); ++} ++ ++late_initcall(omap_vout_init); ++module_exit(omap_vout_cleanup); +diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h +new file mode 100644 +index 0000000..57743e5 +--- /dev/null ++++ b/drivers/media/video/omap/omap_voutdef.h +@@ -0,0 +1,148 @@ ++/* ++ * drivers/media/video/omap/omap_voutdef.h ++ * ++ * Copyright (C) 2009 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 <mach/display.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 3 ++#define MAX_MANAGERS 3 ++ ++/* 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, ++}; ++/* ++ * 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]; ++}; ++ ++struct omap2video_device { ++ struct mutex mtx; ++ ++ int state; ++ ++ struct v4l2_device v4l2_dev; ++ int num_videos; ++ 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; ++ ++}; ++#endif /* ifndef OMAP_VOUTDEF_H */ +diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c +new file mode 100644 +index 0000000..bce5072 +--- /dev/null ++++ b/drivers/media/video/omap/omap_voutlib.c +@@ -0,0 +1,258 @@ ++/* ++ * drivers/media/video/omap/omap_voutlib.c ++ * ++ * Copyright (C) 2005-2009 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) 2009 Texas Instruments. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/videodev2.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 succesful, 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 succesful, 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 limitations */ ++ if ((crop->height/win->w.height) >= 4) { ++ /* The maximum vertical downsizing ratio is 4:1 */ ++ crop->height = win->w.height * 4; ++ } ++ if ((crop->width/win->w.width) >= 4) { ++ /* The maximum horizontal downsizing ratio is 4:1 */ ++ 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 succesful, 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 (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 * crop->height) / win->w.height; ++ if (vresize > 4096) ++ vresize = 4096; ++ else if (vresize == 0) ++ vresize = 1; ++ 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 * crop->width) / win->w.width; ++ if (hresize > 4096) ++ hresize = 4096; ++ else if (hresize == 0) ++ hresize = 1; ++ 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; ++ } ++ ++ /* Check for resizing constraints */ ++ if ((try_crop.height/win->w.height) >= 4) { ++ /* The maximum vertical downsizing ratio is 4:1 */ ++ try_crop.height = win->w.height * 4; ++ } ++ if ((try_crop.width/win->w.width) >= 4) { ++ /* The maximum horizontal downsizing ratio is 4:1 */ ++ 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); ++ +diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/video/omap/omap_voutlib.h +new file mode 100644 +index 0000000..8ef6e25 +--- /dev/null ++++ b/drivers/media/video/omap/omap_voutlib.h +@@ -0,0 +1,34 @@ ++/* ++ * drivers/media/video/omap/omap_voutlib.h ++ * ++ * Copyright (C) 2009 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 ++ ++extern void omap_vout_default_crop(struct v4l2_pix_format *pix, ++ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop); ++ ++extern 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); ++ ++extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf, ++ struct v4l2_window *new_win); ++ ++extern int omap_vout_new_window(struct v4l2_rect *crop, ++ struct v4l2_window *win, struct v4l2_framebuffer *fbuf, ++ struct v4l2_window *new_win); ++ ++extern void omap_vout_new_format(struct v4l2_pix_format *pix, ++ struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop, ++ struct v4l2_window *win); ++#endif /* #ifndef OMAP_LIB_H */ ++ +-- +1.6.2.4 + |