diff options
author | Koen Kooi <koen@openembedded.org> | 2009-03-17 22:51:32 +0100 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2009-03-17 22:51:32 +0100 |
commit | bcde4467f8ac2de9bf9a061f7a3bb3621410d9ef (patch) | |
tree | 9c7f347420619d60fe4216e51f093556d4f48ec0 /recipes | |
parent | 3b7b721db9da9de480a0efc2710e5592b47255fa (diff) |
linux-davinci git: add vfpe driver for davinci and dm355, enable it in dm355-leopard defconfig
Diffstat (limited to 'recipes')
-rw-r--r-- | recipes/linux/linux-davinci/dm355-leopard/defconfig | 127 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/dm355-leopard/vfpe.patch | 143 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe1.patch | 3928 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe2.patch | 200 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe3.patch | 2558 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe4.patch | 1660 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe5.patch | 132 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe6.patch | 224 | ||||
-rw-r--r-- | recipes/linux/linux-davinci/vfpe7.patch | 283 | ||||
-rw-r--r-- | recipes/linux/linux-davinci_git.bb | 12 |
10 files changed, 9253 insertions, 14 deletions
diff --git a/recipes/linux/linux-davinci/dm355-leopard/defconfig b/recipes/linux/linux-davinci/dm355-leopard/defconfig index 8b3f41a716..d8bd0cdc78 100644 --- a/recipes/linux/linux-davinci/dm355-leopard/defconfig +++ b/recipes/linux/linux-davinci/dm355-leopard/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.29-rc7-davinci1 -# Tue Mar 17 20:58:19 2009 +# Tue Mar 17 22:47:40 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -941,19 +941,96 @@ CONFIG_MEDIA_TUNER_XC2028=y CONFIG_MEDIA_TUNER_XC5000=y CONFIG_VIDEO_V4L2=y CONFIG_VIDEO_V4L1=y +CONFIG_VIDEOBUF_GEN=y +CONFIG_VIDEOBUF_DMA_CONTIG=y CONFIG_VIDEO_CAPTURE_DRIVERS=y # CONFIG_VIDEO_ADV_DEBUG is not set # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -CONFIG_VIDEO_HELPER_CHIPS_AUTO=y +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders/decoders and other helper chips +# + +# +# Audio decoders +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TDA9875 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_M52790 is not set +CONFIG_VIDEO_TLV320AIC23B=y +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# Video decoders +# +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_TCM825X is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA7111 is not set +# CONFIG_VIDEO_SAA7114 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7191 is not set +CONFIG_VIDEO_TVP514X=y +CONFIG_VIDEO_TVP5150=y +CONFIG_VIDEO_VPX3220=y + +# +# Video and audio decoders +# +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set # CONFIG_VIDEO_VIVI is not set -# CONFIG_VIDEO_TVP5146 is not set +CONFIG_VIDEO_VPFE_CAPTURE=y +CONFIG_VIDEO_DM355_CCDC=y # CONFIG_VIDEO_CPIA is not set # CONFIG_VIDEO_CPIA2 is not set # CONFIG_VIDEO_SAA5246A is not set # CONFIG_VIDEO_SAA5249 is not set -# CONFIG_SOC_CAMERA is not set +CONFIG_SOC_CAMERA=y +# CONFIG_SOC_CAMERA_MT9M001 is not set +# CONFIG_SOC_CAMERA_MT9M111 is not set +CONFIG_SOC_CAMERA_MT9T031=y +# CONFIG_SOC_CAMERA_MT9V022 is not set +# CONFIG_SOC_CAMERA_TW9910 is not set +CONFIG_SOC_CAMERA_PLATFORM=y +# CONFIG_SOC_CAMERA_OV772X is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set CONFIG_V4L_USB_DRIVERS=y -# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS=y +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y CONFIG_USB_GSPCA=m # CONFIG_USB_M5602 is not set # CONFIG_USB_STV06XX is not set @@ -1010,9 +1087,9 @@ CONFIG_FB=y CONFIG_FIRMWARE_EDID=y # CONFIG_FB_DDC is not set # CONFIG_FB_BOOT_VESA_SUPPORT is not set -# CONFIG_FB_CFB_FILLRECT is not set -# CONFIG_FB_CFB_COPYAREA is not set -# CONFIG_FB_CFB_IMAGEBLIT 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 @@ -1029,7 +1106,7 @@ CONFIG_FIRMWARE_EDID=y # Frame buffer hardware drivers # # CONFIG_FB_S1D13XXX is not set -# CONFIG_FB_DAVINCI is not set +CONFIG_FB_DAVINCI=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set # CONFIG_FB_MB862XX is not set @@ -1052,10 +1129,36 @@ CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y # CONFIG_LOGO is not set -CONFIG_SOUND=m +CONFIG_SOUND=y CONFIG_SOUND_OSS_CORE=y -# CONFIG_SND is not set -CONFIG_SOUND_PRIME=m +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_ARM is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +CONFIG_SND_SOC=y +# CONFIG_SND_DAVINCI_SOC is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +# CONFIG_SOUND_PRIME is not set CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set diff --git a/recipes/linux/linux-davinci/dm355-leopard/vfpe.patch b/recipes/linux/linux-davinci/dm355-leopard/vfpe.patch new file mode 100644 index 0000000000..4c644b6398 --- /dev/null +++ b/recipes/linux/linux-davinci/dm355-leopard/vfpe.patch @@ -0,0 +1,143 @@ +Subject: +[PATCH 7/7] DM355 platform related changes for vpfe capture driver +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:24:34 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Add platform related changes for vpfe capture driver on DM355 + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + arch/arm/mach-davinci/board-dm355-leopard.c | 91 +++++++++++++++++++++++++++- + +diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c +index e104650..aaa58ba 100644 +--- a/arch/arm/mach-davinci/board-dm355-leopard.c ++++ b/arch/arm/mach-davinci/board-dm355-leopard.c +@@ -20,6 +20,8 @@ + #include <linux/io.h> + #include <linux/gpio.h> + #include <linux/clk.h> ++#include <media/v4l2-int-device.h> ++#include <media/tvp514x.h> + #include <linux/spi/spi.h> + #include <linux/spi/eeprom.h> + +@@ -134,12 +136,58 @@ static void dm355leopard_mmcsd_gpios(unsigned gpio) + dm355leopard_mmc_gpios = gpio; + } + ++#define TVP5146_I2C_ADDR 0x5D ++static struct v4l2_ifparm tvp5146_ifparm = { ++ .if_type = V4L2_IF_TYPE_BT656, ++ .u = { ++ .bt656 = { ++ .frame_start_on_rising_vs = 1, ++ .bt_sync_correct = 0, ++ .swap = 0, ++ .latch_clk_inv = 0, ++ .nobt_hs_inv = 0, /* active high */ ++ .nobt_vs_inv = 0, /* active high */ ++ .mode = V4L2_IF_TYPE_BT656_MODE_BT_8BIT, ++ .clock_min = TVP514X_XCLK_BT656, ++ .clock_max = TVP514X_XCLK_BT656, ++ }, ++ }, ++}; ++ ++/** ++ * @brief tvp5146_g_ifparm - Returns the TVP5146 decoder interface parameters ++ * ++ * @param p - pointer to v4l2_ifparm structure ++ * @return result of operation - 0 is success ++ */ ++static int tvp5146_g_ifparm(struct v4l2_ifparm *p) ++{ ++ if (p == NULL) ++ return -EINVAL; ++ ++ *p = tvp5146_ifparm; ++ return 0; ++} ++ ++#define TVP5146_NUM_INPUTS ARRAY_SIZE(tvp5146_input_list) ++ ++static struct tvp514x_platform_data tvp5146_pdata = { ++ .master = CAPTURE_DRV_NAME, ++ .ifparm = tvp5146_g_ifparm, ++ .hs_polarity = 1, ++ .vs_polarity = 1 ++}; ++ + static struct i2c_board_info dm355leopard_i2c_info[] = { +- { I2C_BOARD_INFO("dm355leopard_msp", 0x25), ++ { I2C_BOARD_INFO("dm355leopard_msp", 0x25), + .platform_data = dm355leopard_mmcsd_gpios, +- /* plus irq */ }, ++ }, ++ { ++ I2C_BOARD_INFO("tvp5146", TVP5146_I2C_ADDR), ++ .platform_data = &tvp5146_pdata, ++ }, ++ /* { plus irq }, */ + /* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */ +- /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */ + }; + + static void __init leopard_init_i2c(void) +@@ -178,6 +226,41 @@ static struct platform_device dm355leopard_dm9000 = { + .num_resources = ARRAY_SIZE(dm355leopard_dm9000_rsrc), + }; + ++#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) ++ ++static struct vpfe_capture_input vpfe_capture_inputs = { ++ .num_inputs = VPFE_MAX_DEC_INPUTS, ++ .current_input = 0, ++ .inputs[0] = { ++ .dec_name = TVP514X_MODULE_NAME, ++ .input = { ++ .index = 0, ++ .name = "COMPOSITE", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .std = TVP514X_STD_ALL, ++ }, ++ .route = { ++ .input = INPUT_CVBS_VI2B, ++ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, ++ }, ++ .routing_supported = 1, ++ }, ++ .inputs[1] = { ++ .dec_name = TVP514X_MODULE_NAME, ++ .input = { ++ .index = 1, ++ .name = "SVIDEO", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .std = TVP514X_STD_ALL, ++ }, ++ .route = { ++ .input = INPUT_SVIDEO_VI2C_VI1C, ++ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, ++ }, ++ .routing_supported = 1, ++ }, ++}; ++ + static struct platform_device *davinci_leopard_devices[] __initdata = { + &dm355leopard_dm9000, + &davinci_nand_device, +@@ -190,6 +273,8 @@ static struct davinci_uart_config uart_config __initdata = { + static void __init dm355_leopard_map_io(void) + { + davinci_map_common_io(); ++ /* setup input configuration for VPFE input devices */ ++ setup_vpfe_input_config(&vpfe_capture_inputs); + dm355_init(); + } + diff --git a/recipes/linux/linux-davinci/vfpe1.patch b/recipes/linux/linux-davinci/vfpe1.patch new file mode 100644 index 0000000000..8694d1b7a7 --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe1.patch @@ -0,0 +1,3928 @@ +Subject: +[PATCH 1/7] VPFE capture driver for DM355 and DM6446 +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:15:31 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +This patch is for the vpfe capture driver for DM355 & +DM6446 from Texas instruments. VPFE stands for Video +Processing Front End which is the basic IP on DMxxx +family for video capture and processing. vpfe capture +driver is a v4l2 bridge driver developed based on +v4l2-int-device model. It interfaces slave decoder devices +to the bridge driver using this model. V4L2 community +has already developed a v4l2 sub device model for this +purpose. But at this time, tvp514x, the only slave +decoder that can work with DM355 and DM6446 VPFE, is using +the v4l2-int-device model. So decision is taken to first +use this model to submit the driver to the community and +plan for a migration to sub device model when tvp514x +driver become sub device compliant. + +The driver uses ccdc_hw_device interface to configure +CCDC based on the interface requirement of the slave +decoder device. This driver is integrated with the tvp514x +driver available in open source kernel. The driver is +tested using a loopback application (Will be made +available upon request) that captures video frames from the +capture driver and display it at the output of VPBE using +the FBDev video output device. + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + drivers/media/video/davinci/vpfe_capture.c | 2248 ++++++++++++++++++++++++++++ + drivers/media/video/davinci_vpfe.c | 1136 -------------- + include/media/davinci/vpfe_capture.h | 272 ++++ + include/media/davinci/vpfe_types.h | 71 + + include/media/davinci_vpfe.h | 121 -- + 5 files changed, 2591 insertions(+), 1257 deletions(-) + create mode 100644 drivers/media/video/davinci/vpfe_capture.c + delete mode 100644 drivers/media/video/davinci_vpfe.c + create mode 100644 include/media/davinci/vpfe_capture.h + create mode 100644 include/media/davinci/vpfe_types.h + delete mode 100644 include/media/davinci_vpfe.h + +diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c +new file mode 100644 +index 0000000..decbffc +--- /dev/null ++++ b/drivers/media/video/davinci/vpfe_capture.c +@@ -0,0 +1,2248 @@ ++/* ++ * Copyright (C) 2008-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/interrupt.h> ++#include <linux/version.h> ++#include <media/v4l2-common.h> ++#include <linux/io.h> ++#include <mach/cpu.h> ++#include <media/davinci/vpfe_capture.h> ++#include <media/tvp514x.h> ++static int debug; ++static char *ch0_decoder = "TVP514X"; ++static u32 ch0_numbuffers = 3; ++static u32 ch0_bufsize = (720 * 576 * 2); ++module_param(ch0_decoder, charp, S_IRUGO); ++module_param(ch0_numbuffers, uint, S_IRUGO); ++module_param(ch0_bufsize, uint, S_IRUGO); ++module_param(debug, int, 0); ++ ++static struct vpfe_config_params config_params = { ++ .min_numbuffers = 3, ++ .numbuffers[0] = 3, ++ .min_bufsize[0] = 720 * 480 * 2, ++ .channel_bufsize[0] = 720 * 576 * 2, ++}; ++ ++static int vpfe_nr[] = { 0 }; ++ ++static struct vpfe_device vpfe_obj = { {NULL} }; ++static struct device *vpfe_dev; ++ ++static struct v4l2_capability vpfe_videocap = { ++ .driver = CAPTURE_DRV_NAME, ++ .card = "DaVinci EVM", ++ .bus_info = "Platform", ++ .version = VPFE_CAPTURE_VERSION_CODE, ++ .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING ++}; ++ ++#define VPFE_PIXELASPECT_NTSC {11, 10} ++#define VPFE_PIXELASPECT_PAL {54, 59} ++ ++/* standard information */ ++struct vpfe_standard { ++ v4l2_std_id std_id; ++ unsigned int width; ++ unsigned int height; ++ struct v4l2_fract pixelaspect; ++ /* 0 - progressive, 1 - interlaced */ ++ char frame_format; ++}; ++ ++struct vpfe_standard vpfe_standards[] = { ++ {V4L2_STD_NTSC, 720, 480, VPFE_PIXELASPECT_NTSC, 1}, ++ {V4L2_STD_PAL, 720, 576, VPFE_PIXELASPECT_PAL, 1}, ++}; ++ ++static int vpfe_max_standards = ARRAY_SIZE(vpfe_standards); ++ ++/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ ++static struct vpfe_pixel_format ++ vpfe_pix_fmts[VPFE_MAX_PIX_FORMATS] = { ++ { ++ .pix_fmt = V4L2_PIX_FMT_SBGGR8, ++ .desc = "Raw Bayer GrRBGb 8bit A-Law compressed", ++ .hw_fmt = VPFE_BAYER_8BIT_PACK_ALAW, ++ }, ++ { ++ .pix_fmt = V4L2_PIX_FMT_SBGGR16, ++ .desc = "Raw Bayer GrRBGb - 16bit", ++ .hw_fmt = VPFE_BAYER, ++ }, ++ { ++ .pix_fmt = V4L2_PIX_FMT_SGRBG10DPCM8, ++ .desc = "Raw Bayer GrRBGb 8 bit DPCM compressed", ++ .hw_fmt = VPFE_BAYER_8BIT_PACK_DPCM, ++ }, ++ { ++ .pix_fmt = V4L2_PIX_FMT_UYVY, ++ .desc = "YCbCr 4:2:2 Interleaved UYVY", ++ .hw_fmt = VPFE_UYVY, ++ }, ++ { ++ .pix_fmt = V4L2_PIX_FMT_YUYV, ++ .desc = "YCbCr 4:2:2 Interleaved YUYV", ++ .hw_fmt = VPFE_YUYV, ++ }, ++ { ++ .pix_fmt = V4L2_PIX_FMT_NV12, ++ .desc = "Y/CbCr 4:2:0 - Semi planar", ++ .hw_fmt = VPFE_YUV420, ++ }, ++}; ++ ++ ++static int vpfe_lookup_hw_format(u32 pix_format) ++{ ++ int i, ret = -EINVAL; ++ ++ for (i = 0; i < VPFE_MAX_PIX_FORMATS; i++) { ++ if (pix_format == vpfe_pix_fmts[i].pix_fmt) { ++ ret = i; ++ break; ++ } ++ } ++ return ret; ++} ++ ++static int vpfe_lookup_v4l2_pix_format(enum vpfe_hw_pix_format hw_pix) ++{ ++ int i, ret = -EINVAL; ++ ++ for (i = 0; i < VPFE_MAX_PIX_FORMATS; i++) { ++ if (hw_pix == vpfe_pix_fmts[i].hw_fmt) { ++ ret = i; ++ break; ++ } ++ } ++ return ret; ++} ++ ++ ++/* Used when raw YUV image from ccdc is directly captured to SDRAM */ ++static void vpfe_slave_device_unregister(struct v4l2_int_device *s) ++{ ++ int index; ++ struct channel_obj *channel = s->u.slave->master->priv; ++ ++ for (index = 0; index < VPFE_CAPTURE_NUM_DECODERS; index++) { ++ if ((channel->decoder[index] == s) ++ && (index == channel->current_decoder)) { ++ if (channel->common->started) { ++ /* Streaming is ON. So return busy */ ++ v4l2_err(vpfe_dev->driver, ++ "Steaming ON. Cannot unregister" ++ "decoder %s\n", s->name); ++ return; ++ } else { ++ channel->decoder[index] = NULL; ++ channel->numdecoders--; ++ break; ++ } ++ } ++ } ++ if (index == VPFE_CAPTURE_NUM_DECODERS) ++ v4l2_err(vpfe_dev->driver, ++ "No matching decoder registered" ++ "decoder %s\n", s->name); ++} ++ ++static int vpfe_get_stdinfo(struct channel_obj *ch, v4l2_std_id *std_id) ++{ ++ int i; ++ struct video_obj *vid_ch = NULL; ++ ++ vid_ch = &(ch->video); ++ ++ for (i = 0; i < vpfe_max_standards; i++) { ++ if (vpfe_standards[i].std_id == *std_id) { ++ vid_ch->std_info.activepixels = ++ vpfe_standards[i].width; ++ vid_ch->std_info.activelines = ++ vpfe_standards[i].height; ++ vid_ch->std_info.frame_format = ++ vpfe_standards[i].frame_format; ++ vid_ch->index = i; ++ break; ++ } ++ } ++ if (i == vpfe_max_standards) { ++ v4l2_err(vpfe_dev->driver, "standard not supported\n"); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/* vpfe_device_register: Used for registering a slave decoder ++ * device with master ++ */ ++static int vpfe_slave_device_register(struct v4l2_int_device *s) ++{ ++ struct channel_obj *channel = s->u.slave->master->priv; ++ struct common_obj *common = &channel->common[VPFE_VIDEO_INDEX]; ++ int err = 0, index; ++ dev_notice(vpfe_dev, "register slave %s \n", s->name); ++ if (ISNULL(channel)) ++ return -EINVAL; ++ ++ if (!channel->numdecoders) { ++ if (!vidioc_int_dev_init(s)) { ++ channel->current_decoder = 0; ++ channel->decoder[channel->current_decoder] = s; ++ v4l2_info(vpfe_dev->driver, "Current decoder is set to" ++ " %s\n", (s->name)); ++ } ++ } else { ++ /* search through the array for an empty entry */ ++ for (index = 0; index < VPFE_CAPTURE_NUM_DECODERS; index++) { ++ if (ISNULL(channel->decoder[index])) { ++ channel->decoder[index] = s; ++ break; ++ } ++ } ++ if (index == VPFE_CAPTURE_NUM_DECODERS) { ++ v4l2_err(vpfe_dev->driver, ++ "decoder count reached" ++ " maximum allowed\n"); ++ return -ENOMEM; ++ } ++ if (!strncmp(ch0_decoder, s->name, strlen(ch0_decoder))) { ++ if (!common->started) { ++ if (!vidioc_int_dev_init(s)) { ++ channel->current_decoder = index; ++ v4l2_info(vpfe_dev->driver, ++ "Current decoder is" ++ " set to %s\n", (s->name)); ++ } ++ } ++ } ++ } ++ channel->numdecoders++; ++ return err; ++} ++ ++/* vpfe capture master. All slave decoders registers ++ * with master using vpfe_device_register and deregisters ++ * using vpfe_slave_device_unregister ++ */ ++static struct v4l2_int_master vpfe_master = { ++ .attach = vpfe_slave_device_register, ++ .detach = vpfe_slave_device_unregister, ++}; ++ ++static struct v4l2_int_device vpfe_capture = { ++ .module = THIS_MODULE, ++ .name = CAPTURE_DRV_NAME, ++ .type = v4l2_int_type_master, ++ .u = { ++ .master = &vpfe_master ++ }, ++}; ++ ++/* Call this after storing ifparams in channel block */ ++static int vpfe_set_hw_if_type(struct channel_obj *channel) ++{ ++ struct vpfe_capture_input *input = channel->video.input; ++ ++ switch (input->inputs[input->current_input].route.output) { ++ case OUTPUT_10BIT_422_EMBEDDED_SYNC: ++ channel->vpfe_if = VPFE_BT656; ++ break; ++ case OUTPUT_20BIT_422_SEPERATE_SYNC: ++ channel->vpfe_if = VPFE_YCBCR_SYNC_16; ++ break; ++ case OUTPUT_10BIT_422_SEPERATE_SYNC: ++ channel->vpfe_if = VPFE_YCBCR_SYNC_8; ++ default: ++ v4l2_err(vpfe_dev->driver, "decoder output" ++ " not supported, %d\n", ++ input->inputs[input->current_input].route.output); ++ return -EFAULT; ++ } ++ return ccdc_hw_dev.set_hw_if_type(channel->vpfe_if); ++} ++ ++static int vpfe_get_image_format(struct v4l2_format *f) ++{ ++ struct v4l2_rect image_win; ++ enum ccdc_buftype buf_type; ++ enum ccdc_frmfmt frm_fmt; ++ enum vpfe_hw_pix_format hw_pix; ++ int ret = 0; ++ ++ memset(f, 0, sizeof(struct v4l2_format)); ++ f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ccdc_hw_dev.get_image_window(&image_win); ++ f->fmt.pix.width = image_win.width; ++ f->fmt.pix.height = image_win.height; ++ ccdc_hw_dev.get_line_length(&f->fmt.pix.bytesperline); ++ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * ++ f->fmt.pix.height; ++ ccdc_hw_dev.get_buftype(&buf_type); ++ ccdc_hw_dev.get_pixelformat(&hw_pix); ++ ++ if (hw_pix == VPFE_BAYER) ++ f->fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR16; ++ else if (hw_pix == VPFE_BAYER_8BIT_PACK_ALAW) ++ f->fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; ++ else if (hw_pix == VPFE_UYVY) ++ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; ++ else if (hw_pix == VPFE_YUYV) ++ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; ++ else { ++ v4l2_err(vpfe_dev->driver, "Invalid HW pix format detected"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ccdc_hw_dev.get_frame_format(&frm_fmt); ++ if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { ++ if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) ++ f->fmt.pix.field = V4L2_FIELD_INTERLACED; ++ else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) ++ f->fmt.pix.field = V4L2_FIELD_SEQ_TB; ++ else ++ ret = -EINVAL; ++ } else ++ ret = -EINVAL; ++out: ++ return ret; ++} ++ ++/* vpfe_config_default_format: Update format information */ ++static int vpfe_config_default_format(struct channel_obj *ch) ++{ ++ struct common_obj *common = &(ch->common[VPFE_VIDEO_INDEX]); ++ struct v4l2_int_device *dec = ch->decoder[ch->current_decoder]; ++ struct v4l2_rect win; ++ int err = 0; ++ struct video_obj *vid_ch = NULL; ++ ++ vid_ch = &(ch->video); ++ common->crop.top = 0; ++ common->crop.left = 0; ++ /* first get format information from the decoder. ++ * if not available, get it from CCDC ++ */ ++ if ((vidioc_int_g_fmt_cap(dec, &common->fmt)) < 0) ++ vpfe_get_image_format(&common->fmt); ++ else { ++ /* set up all parameters in CCDC */ ++ win.top = common->crop.top; ++ win.left = common->crop.left; ++ win.width = common->fmt.fmt.pix.width; ++ win.height = common->fmt.fmt.pix.height; ++ ccdc_hw_dev.set_image_window(&win); ++ if (common->fmt.fmt.pix.field == ++ V4L2_FIELD_INTERLACED) { ++ err |= ++ ccdc_hw_dev.set_buftype(CCDC_BUFTYPE_FLD_INTERLEAVED); ++ err |= ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_INTERLACED); ++ } else if (common->fmt.fmt.pix.field == ++ V4L2_FIELD_SEQ_TB) { ++ err |= ++ ccdc_hw_dev.set_buftype(CCDC_BUFTYPE_FLD_SEPARATED); ++ err |= ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_INTERLACED); ++ } else if (common->fmt.fmt.pix.field == ++ V4L2_FIELD_NONE) { ++ err |= ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_PROGRESSIVE); ++ } else { ++ v4l2_dbg(1, debug, vpfe_dev->driver, ++ "\n Decoder field not supported!"); ++ err = -EINVAL; ++ goto out; ++ } ++ } ++ /* set the crop limits */ ++ vid_ch->std_info.activepixels = common->fmt.fmt.pix.width; ++ vid_ch->std_info.activelines = common->fmt.fmt.pix.height; ++ if (config_params.numbuffers[ch->channel_id] == 0) ++ common->memory = V4L2_MEMORY_USERPTR; ++ else ++ common->memory = V4L2_MEMORY_MMAP; ++out: ++ return err; ++} ++ ++static int vpfe_initialize_channel(struct channel_obj *channel, ++ struct v4l2_int_device *dec) ++{ ++ struct common_obj *common = NULL; ++ struct video_obj *vid_ch = NULL; ++ int err = 0; ++ ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ vid_ch = &(channel->video); ++ channel->out_from = VPFE_CCDC_OUT; ++ vid_ch->input->current_input = 0; ++ ++ err = vidioc_int_g_ifparm(dec, &channel->ifparams); ++ if (err) { ++ v4l2_err(vpfe_dev->driver, ++ "vidioc_int_g_ifparm failed with %d\n", err); ++ return err; ++ } ++ ++ err = vpfe_set_hw_if_type(channel); ++ if (err) ++ return err; ++ ++ /* Initialize decoder by calling initialize function */ ++ err = vidioc_int_s_power(dec, 1); ++ if (err) { ++ v4l2_err(vpfe_dev->driver, ++ "unable to power on the decoder, %s, error %d\n", ++ dec->name, ++ err); ++ return err; ++ } ++ ++ err = vidioc_int_init(dec); ++ if (err) { ++ v4l2_err(vpfe_dev->driver, ++ "cannot initialize decoder - error %d\n", ++ err); ++ return err; ++ } ++ ++ /* Configure the default format information */ ++ err = vpfe_config_default_format(channel); ++ ++ /* now open the ccdc device to initialize it */ ++ ccdc_hw_dev.open(vpfe_dev); ++ channel->initialized = 1; ++ return err; ++} ++ ++/* vpfe_open : It creates object of file handle structure and ++ * stores it in private_data member of filepointer ++ */ ++static int vpfe_open(struct file *filep) ++{ ++ int minor = iminor(filep->f_path.dentry->d_inode); ++ struct channel_obj *channel = NULL; ++ struct v4l2_int_device *dec = NULL; ++ struct common_obj *common = NULL; ++ struct vpfe_fh *fh = NULL; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "vpfe_open\n"); ++ ++ /* Check for valid minor number */ ++ channel = vpfe_obj.dev[0]; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ if (minor != channel->video_dev->minor) { ++ v4l2_err(vpfe_dev->driver, "device not found\n"); ++ return -ENODEV; ++ } ++ ++ if (!channel->numdecoders) { ++ v4l2_err(vpfe_dev->driver, "No decoder registered\n"); ++ return -ENODEV; ++ } ++ ++ dec = channel->decoder[channel->current_decoder]; ++ ++ /* Allocate memory for the file handle object */ ++ fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); ++ if (ISNULL(fh)) { ++ v4l2_err(vpfe_dev->driver, ++ "unable to allocate memory for file handle object\n"); ++ return -ENOMEM; ++ } ++ /* store pointer to fh in private_data member of filep */ ++ filep->private_data = fh; ++ fh->channel = channel; ++ fh->initialized = 0; ++ /* If decoder is not initialized. initialize it */ ++ if (!channel->initialized) { ++ if (vpfe_initialize_channel(channel, dec)) ++ return -ENODEV; ++ fh->initialized = 1; ++ } ++ /* Increment channel usrs counter */ ++ channel->usrs++; ++ /* Set io_allowed member to false */ ++ fh->io_allowed[VPFE_VIDEO_INDEX] = 0; ++ /* Initialize priority of this instance to default priority */ ++ fh->prio = V4L2_PRIORITY_UNSET; ++ v4l2_prio_open(&channel->prio, &fh->prio); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_open>\n"); ++ return 0; ++} ++ ++/*ISR for VINT0*/ ++static irqreturn_t vpfe_isr(int irq, void *dev_id) ++{ ++ struct timeval timevalue; ++ struct channel_obj *channel = NULL; ++ struct common_obj *common = NULL; ++ struct video_obj *vid_ch = NULL; ++ struct vpfe_device *dev = dev_id; ++ unsigned long addr; ++ int fid; ++ enum v4l2_field field; ++ channel = dev->dev[VPFE_CHANNEL0_VIDEO]; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ vid_ch = &(channel->video); ++ field = common->fmt.fmt.pix.field; ++ do_gettimeofday(&timevalue); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "\nStarting vpfe_isr..."); ++ ++ /* only for 6446 this will be applicable */ ++ if (!(ISNULL(ccdc_hw_dev.reset))) ++ ccdc_hw_dev.reset(); ++ ++ if (field == V4L2_FIELD_INTERLACED || ++ (field == V4L2_FIELD_SEQ_TB)) { ++ /* Interlaced */ ++ /* check which field we are in hardware */ ++ fid = ccdc_hw_dev.getfid(); ++ /* switch the software maintained field id */ ++ channel->field_id ^= 1; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "field id = %x:%x.\n", fid, ++ channel->field_id); ++ if (fid == channel->field_id) { ++ /* we are in-sync here,continue */ ++ if (fid == 0) { ++ /* One frame is just being captured. If the ++ * next frame is available, release the current ++ * frame and move on ++ */ ++ if (common->curFrm != common->nextFrm) { ++ /* Copy frame capture time value in ++ * curFrm->ts ++ */ ++ common->curFrm->ts = timevalue; ++ common->curFrm->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&common->curFrm-> ++ done); ++ common->curFrm = common->nextFrm; ++ } ++ /* based on whether the two fields are stored ++ * interleavely or separately in memory, ++ * reconfigure the CCDC memory address ++ */ ++ if (channel->out_from == VPFE_CCDC_OUT && ++ field == V4L2_FIELD_SEQ_TB) { ++ addr = ++ videobuf_to_dma_contig(common->curFrm); ++ addr += common->field_off; ++ ccdc_hw_dev.setfbaddr(addr); ++ } ++ } else if (fid == 1) { ++ /* if one field is just being captured ++ * configure the next frame ++ * get the next frame from the empty queue ++ * if no frame is available ++ * hold on to the current buffer ++ */ ++ if (channel->out_from == VPFE_CCDC_OUT && ++ !list_empty(&common->dma_queue) && ++ common->curFrm == common->nextFrm) { ++ common->nextFrm = ++ list_entry(common-> ++ dma_queue.next, ++ struct ++ videobuf_buffer, ++ queue); ++ list_del(&common->nextFrm->queue); ++ common->nextFrm->state = ++ VIDEOBUF_ACTIVE; ++ addr = videobuf_to_dma_contig(common-> ++ nextFrm); ++ ccdc_hw_dev.setfbaddr(addr); ++ } ++ } ++ } else if (fid == 0) { ++ /* recover from any hardware out-of-sync due to ++ * possible switch of video source ++ * for fid == 0, sync up the two fids ++ * for fid == 1, no action, one bad frame will ++ * go out, but it is not a big deal ++ */ ++ channel->field_id = fid; ++ } ++ } else if (field == V4L2_FIELD_NONE) { ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, ++ "\nframe format is progressive..."); ++ if (common->curFrm != common->nextFrm) { ++ /* Copy frame capture time value in curFrm->ts */ ++ common->curFrm->ts = timevalue; ++ common->curFrm->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&common->curFrm->done); ++ common->curFrm = common->nextFrm; ++ } ++ ++ } ++ v4l2_dbg(1, debug, vpfe_dev->driver, "interrupt returned.\n"); ++ return IRQ_RETVAL(1); ++} ++ ++static irqreturn_t vdint1_isr(int irq, void *dev_id) ++{ ++ struct channel_obj *channel = NULL; ++ struct common_obj *common = NULL; ++ struct vpfe_device *dev = dev_id; ++ unsigned long addr; ++ channel = dev->dev[VPFE_CHANNEL0_VIDEO]; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "\nInside vdint1_isr..."); ++ ++ if ((common->fmt.fmt.pix.field == V4L2_FIELD_NONE) && ++ !list_empty(&common->dma_queue) && ++ common->curFrm == common->nextFrm) { ++ common->nextFrm = ++ list_entry(common->dma_queue.next, ++ struct videobuf_buffer, queue); ++ list_del(&common->nextFrm->queue); ++ common->nextFrm->state = VIDEOBUF_ACTIVE; ++ addr = videobuf_to_dma_contig(common->nextFrm); ++ ccdc_hw_dev.setfbaddr(addr); ++ } ++ return IRQ_RETVAL(1); ++} ++ ++static int vpfe_detach_irq(struct channel_obj *channel) ++{ ++ enum ccdc_frmfmt frame_format; ++ int err = 0; ++ ++ /* First clear irq if already in use */ ++ switch (channel->irq_type) { ++ case VPFE_USE_CCDC_IRQ: ++ ccdc_hw_dev.get_frame_format(&frame_format); ++ if (frame_format == CCDC_FRMFMT_PROGRESSIVE) ++ free_irq(IRQ_VDINT1, &vpfe_obj); ++ channel->irq_type = VPFE_NO_IRQ; ++ break; ++ case VPFE_NO_IRQ: ++ break; ++ default: ++ return -1; ++ } ++ return err; ++} ++ ++static int vpfe_attach_irq(struct channel_obj *channel) ++{ ++ enum ccdc_frmfmt frame_format; ++ int err = 0; ++ ++ channel->irq_type = VPFE_USE_CCDC_IRQ; ++ ++ switch (channel->irq_type) { ++ case VPFE_USE_CCDC_IRQ: ++ { ++ ccdc_hw_dev.get_frame_format(&frame_format); ++ if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { ++ err = ++ request_irq(channel->ccdc_irq1, ++ vdint1_isr, ++ IRQF_DISABLED, ++ "vpfe_capture1", ++ (void *)&vpfe_obj); ++ if (err < 0) ++ return -1; ++ } ++ } ++ break; ++ default: ++ return -1; ++ } ++ return 0; ++} ++ ++/* vpfe_release : This function deletes buffer queue, frees the ++ * buffers and the vpfe file handle ++ */ ++static int vpfe_release(struct file *filep) ++{ ++ int ret; ++ struct common_obj *common = NULL; ++ /* Get the channel object and file handle object */ ++ struct vpfe_fh *fh = filep->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_release>\n"); ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ /* If this is doing IO and other channels are not closed */ ++ if ((channel->usrs != 1) && fh->io_allowed[VPFE_VIDEO_INDEX]) { ++ v4l2_err(vpfe_dev->driver, "Close other instances\n"); ++ return -EAGAIN; ++ } ++ /* Get the lock on channel object */ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ return ret; ++ /* if this instance is doing IO */ ++ if (fh->io_allowed[VPFE_VIDEO_INDEX]) { ++ /* Reset io_usrs member of channel object */ ++ if (common->started) { ++ ccdc_hw_dev.enable(0); ++ if (ccdc_hw_dev.enable_out_to_sdram) ++ ccdc_hw_dev.enable_out_to_sdram(0); ++ if (vpfe_detach_irq(channel) < 0) { ++ v4l2_err(vpfe_dev->driver, ++ "Error in detaching IRQ\n"); ++ mutex_unlock(&common->lock); ++ return -EFAULT; ++ } ++ } ++ ++ common->io_usrs = 0; ++ /* Disable channel/vbi as per its device type and channel id */ ++ common->started = 0; ++ /* Free buffers allocated */ ++ common->numbuffers = ++ config_params.numbuffers[channel->channel_id]; ++ } ++ ++ /* Decrement channel usrs counter */ ++ channel->usrs--; ++ /* unlock semaphore on channel object */ ++ mutex_unlock(&common->lock); ++ /* Close the priority */ ++ v4l2_prio_close(&channel->prio, &fh->prio); ++ /* If this file handle has initialize decoder device, reset it */ ++ if (fh->initialized) { ++ vidioc_int_s_power(dec, 0); ++ channel->initialized = 0; ++ if (ccdc_hw_dev.close) ++ ccdc_hw_dev.close(vpfe_dev); ++ } ++ filep->private_data = NULL; ++ /* Free memory allocated to file handle object */ ++ kfree(fh); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_release>\n"); ++ return 0; ++} ++ ++/* vpfe_mmap : It is used to map kernel space buffers ++ * into user spaces ++ */ ++static int vpfe_mmap(struct file *filep, struct vm_area_struct *vma) ++{ ++ /* Get the channel object and file handle object */ ++ struct vpfe_fh *fh = filep->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common; ++ int err = 0; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "Start of vpfe mmap\n"); ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ err = videobuf_mmap_mapper(&common->buffer_queue, vma); ++ v4l2_dbg(1, debug, vpfe_dev->driver, "End of vpfe mmap\n"); ++ return err; ++} ++ ++/* vpfe_poll: It is used for select/poll system call ++ */ ++static unsigned int vpfe_poll(struct file *filep, poll_table *wait) ++{ ++ int err = 0; ++ struct vpfe_fh *fh = filep->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_poll>"); ++ ++ if (common->started) ++ err = videobuf_poll_stream(filep, &common->buffer_queue, wait); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_poll>"); ++ return err; ++} ++ ++/* vpfe capture driver file operations */ ++static struct v4l2_file_operations vpfe_fops = { ++ .owner = THIS_MODULE, ++ .open = vpfe_open, ++ .release = vpfe_release, ++ .ioctl = video_ioctl2, ++ .mmap = vpfe_mmap, ++ .poll = vpfe_poll ++}; ++ ++static struct vpfe_pixel_format * ++ vpfe_check_format(struct channel_obj *channel, ++ struct v4l2_pix_format *pixfmt, ++ int check) ++{ ++ struct common_obj *common = &(channel->common[VPFE_VIDEO_INDEX]); ++ struct video_obj *vid_ch = &(channel->video); ++ struct vpfe_pixel_format *pix_fmt; ++ enum vpfe_hw_pix_format hw_pix; ++ int temp, found, hpitch, vpitch, bpp, min_height = 1, ++ min_width = 32, max_width, max_height; ++ ++ ++ temp = vpfe_lookup_hw_format(pixfmt->pixelformat); ++ if (temp < 0) { ++ if (check) { ++ v4l2_err(vpfe_dev->driver, "invalid pixel format\n"); ++ return NULL; ++ } ++ /* if invalid and this is a try format, then use hw default */ ++ pixfmt->pixelformat = common->fmt.fmt.pix.pixelformat; ++ /* Since this is hw default, we will find this pix format */ ++ temp = vpfe_lookup_hw_format(pixfmt->pixelformat); ++ ++ } else { ++ /* check if hw supports it */ ++ pix_fmt = &vpfe_pix_fmts[temp]; ++ temp = 0; ++ found = 0; ++ while (ccdc_hw_dev.enum_pix(&hw_pix, temp) >= 0) { ++ if (pix_fmt->hw_fmt == hw_pix) { ++ found = 1; ++ break; ++ } ++ temp++; ++ } ++ if (!found) { ++ if (check) { ++ v4l2_err(vpfe_dev->driver, "hw doesn't" ++ "support the pixel format\n"); ++ return NULL; ++ } ++ /* Since this is hw default, we will find this ++ * pix format ++ */ ++ pixfmt->pixelformat = common->fmt.fmt.pix.pixelformat; ++ temp = vpfe_lookup_hw_format(pixfmt->pixelformat); ++ } ++ } ++ pix_fmt = &vpfe_pix_fmts[temp]; ++ if (pixfmt->field == V4L2_FIELD_ANY) { ++ /* if ANY set the field to match with decoder */ ++ pixfmt->field = common->fmt.fmt.pix.field; ++ } ++ ++ /* Try matching the field with the decoder scan field */ ++ if (common->fmt.fmt.pix.field != pixfmt->field) { ++ if (!(VPFE_VALID_FIELD(pixfmt->field)) && check) { ++ v4l2_err(vpfe_dev->driver, "invalid field format\n"); ++ return NULL; ++ } ++ if (common->fmt.fmt.pix.field == V4L2_FIELD_INTERLACED) { ++ if (pixfmt->field != V4L2_FIELD_SEQ_TB) { ++ if (check) { ++ v4l2_err(vpfe_dev->driver, ++ "invalid field format\n"); ++ return NULL; ++ } ++ pixfmt->field = common->fmt.fmt.pix.field; ++ } ++ } else if (common->fmt.fmt.pix.field == V4L2_FIELD_NONE) { ++ if (check) { ++ v4l2_err(vpfe_dev->driver, ++ "invalid field format\n"); ++ return NULL; ++ } ++ pixfmt->field = common->fmt.fmt.pix.field; ++ } else ++ pixfmt->field = common->fmt.fmt.pix.field; ++ } ++ ++ if (pixfmt->field == V4L2_FIELD_INTERLACED) ++ min_height = 2; ++ ++ max_width = vid_ch->std_info.activepixels; ++ max_height = vid_ch->std_info.activelines; ++ if ((pixfmt->pixelformat == V4L2_PIX_FMT_SBGGR8) || ++ (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) || ++ (pixfmt->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)) ++ bpp = 1; ++ else ++ bpp = 2; ++ min_width /= bpp; ++ hpitch = pixfmt->width; ++ vpitch = pixfmt->height; ++ v4l2_info(vpfe_dev->driver, "hpitch = %d, vpitch = %d, bpp = %d\n", ++ hpitch, vpitch, bpp); ++ if (hpitch < min_width) ++ hpitch = min_width; ++ if (vpitch < min_width) ++ vpitch = min_height; ++ ++ /* Check for upper limits of pitch */ ++ if (hpitch > max_width) ++ hpitch = max_width; ++ if (vpitch > max_height) ++ vpitch = max_height; ++ ++ /* recalculate bytesperline and sizeimage since width ++ * and height might have changed ++ */ ++ pixfmt->bytesperline = (((hpitch * bpp) + 31) & ~31); ++ if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) ++ pixfmt->sizeimage = pixfmt->bytesperline * vpitch + ++ ((pixfmt->bytesperline * vpitch) >> 1); ++ else ++ pixfmt->sizeimage = pixfmt->bytesperline * vpitch; ++ pixfmt->width = hpitch; ++ pixfmt->height = vpitch; ++ v4l2_info(vpfe_dev->driver, "adjusted hpitch = %d, vpitch =" ++ " %d, bpp = %d\n", hpitch, vpitch, bpp); ++ return pix_fmt; ++} ++ ++static int vpfe_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_QUERYCAP\n"); ++ memset(cap, 0, sizeof(*cap)); ++ if ((VPFE_CHANNEL0_VIDEO == channel->channel_id)) ++ *cap = vpfe_videocap; ++ else ++ return -EINVAL; ++ return 0; ++} ++ ++static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_G_FMT\n"); ++ /* Fill in the information about ++ * format ++ */ ++ ret = mutex_lock_interruptible(&(common->lock)); ++ if (ret) ++ goto lock_out; ++ *fmt = common->fmt; ++lock_out: ++ mutex_unlock(&(common->lock)); ++ return ret; ++} ++ ++static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *fmt) ++{ ++ int ret; ++ enum vpfe_hw_pix_format hw_pix; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_ENUM_FMT\n"); ++ /* Fill in the information about format */ ++ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ret = ccdc_hw_dev.enum_pix(&hw_pix, fmt->index); ++ if (!ret) { ++ ret = vpfe_lookup_v4l2_pix_format(hw_pix); ++ if (ret >= 0) { ++ strcpy(fmt->description, vpfe_pix_fmts[ret].desc); ++ fmt->pixelformat = vpfe_pix_fmts[ret].pix_fmt; ++ ret = 0; ++ } ++ } ++ return ret; ++} ++ ++static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ struct v4l2_rect win; ++ struct vpfe_pixel_format *pix_fmts; ++ int ret = 0; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_S_FMT\n"); ++ /* If streaming is started, return error */ ++ if (common->started) { ++ v4l2_err(vpfe_dev->driver, "Streaming is started\n"); ++ ret = -EBUSY; ++ goto out; ++ } ++ /* Check for valid frame format */ ++ pix_fmts = vpfe_check_format(channel, &fmt->fmt.pix, 1); ++ ++ if (ISNULL(pix_fmts)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* store the pixel format in the channel ++ * object */ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ ++ /* First detach any IRQ if currently attached */ ++ if (vpfe_detach_irq(channel) < 0) { ++ v4l2_err(vpfe_dev->driver, "Error in detaching IRQ\n"); ++ ret = -EFAULT; ++ goto lock_out; ++ } ++ ++ common->fmt = *fmt; ++ ++ /* we are using same variable for setting crop window ++ * at ccdc. For ccdc, this is same as ++ * image window ++ */ ++ ccdc_hw_dev.get_image_window(&win); ++ win.width = common->fmt.fmt.pix.width; ++ win.height = common->fmt.fmt.pix.height; ++ ccdc_hw_dev.set_image_window(&win); ++ ++ /* In this case, image window and crop window are ++ * the same ++ */ ++ if (common->fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR16) ++ ccdc_hw_dev.set_pixelformat(VPFE_BAYER); ++ else if (common->fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) ++ ccdc_hw_dev.set_pixelformat(VPFE_BAYER_8BIT_PACK_ALAW); ++ else if (common->fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ++ ccdc_hw_dev.set_pixelformat(VPFE_UYVY); ++ else if (common->fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) ++ ccdc_hw_dev.set_pixelformat(VPFE_YUYV); ++ else { ++ /* invalid pix format */ ++ ret = -EINVAL; ++ goto lock_out; ++ } ++ if (common->fmt.fmt.pix.field == ++ V4L2_FIELD_INTERLACED) { ++ ccdc_hw_dev.set_buftype(CCDC_BUFTYPE_FLD_INTERLEAVED); ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_INTERLACED); ++ } else if (common->fmt.fmt.pix.field == ++ V4L2_FIELD_SEQ_TB) { ++ ccdc_hw_dev.set_buftype(CCDC_BUFTYPE_FLD_SEPARATED); ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_INTERLACED); ++ } else if (common->fmt.fmt.pix.field == V4L2_FIELD_NONE) ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_PROGRESSIVE); ++ else { ++ v4l2_err(vpfe_dev->driver, "\n field error!"); ++ ret = -EINVAL; ++ } ++lock_out: ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct vpfe_pixel_format *pix_fmts; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_TRY_FMT\n"); ++ ++ pix_fmts = vpfe_check_format(channel, &f->fmt.pix, 0); ++ if (ISNULL(pix_fmts)) ++ return -EINVAL; ++ return 0; ++} ++ ++static void vpfe_config_format(struct channel_obj *ch) ++{ ++ struct common_obj *common = &(ch->common[VPFE_VIDEO_INDEX]); ++ struct v4l2_rect win; ++ struct video_obj *vid_ch = NULL; ++ ++ vid_ch = &(ch->video); ++ common->crop.top = 0; ++ common->crop.top = 0; ++ common->crop.width = common->fmt.fmt.pix.width = ++ vid_ch->std_info.activepixels; ++ common->crop.height = common->fmt.fmt.pix.height = ++ vid_ch->std_info.activelines; ++ win.top = common->crop.top; ++ win.left = common->crop.left; ++ win.width = common->fmt.fmt.pix.width; ++ win.height = common->fmt.fmt.pix.height; ++ ccdc_hw_dev.set_image_window(&win); ++ if (vid_ch->std_info.frame_format) { ++ common->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_INTERLACED); ++ ccdc_hw_dev.set_buftype(CCDC_BUFTYPE_FLD_INTERLEAVED); ++ } else { ++ common->fmt.fmt.pix.field = V4L2_FIELD_NONE; ++ ccdc_hw_dev.set_frame_format(CCDC_FRMFMT_PROGRESSIVE); ++ } ++ ccdc_hw_dev.get_line_length(&common->fmt.fmt.pix.bytesperline); ++ common->fmt.fmt.pix.sizeimage = common->fmt.fmt.pix.bytesperline * ++ common->fmt.fmt.pix.height; ++} ++ ++static int vpfe_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct vpfe_capture_input *vpfe_inputs = channel->video.input; ++ int ret = -EINVAL; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_ENUMINPUT\n"); ++ ++ if (inp->index > vpfe_inputs->num_inputs) ++ return ret; ++ ++ if (vpfe_inputs->inputs[inp->index].input.name[0]) { ++ memcpy(inp, &vpfe_inputs->inputs[inp->index].input, ++ sizeof(struct v4l2_input)); ++ return 0; ++ } ++ return ret; ++} ++ ++static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = ++ &(channel->common[VPFE_VIDEO_INDEX]); ++ struct vpfe_capture_input *vpfe_inputs = channel->video.input; ++ int ret = 0; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_G_INPUT\n"); ++ ret = mutex_lock_interruptible(&common->lock); ++ if (!ret) ++ *index = vpfe_inputs->current_input; ++ mutex_unlock(&common->lock); ++ return ret; ++} ++ ++ ++static int vpfe_s_input(struct file *file, void *priv, unsigned int index) ++{ ++ int i, ret = -EINVAL; ++ v4l2_std_id std_id; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct v4l2_int_device *new_dec, *curr_dec = ++ channel->decoder[channel->current_decoder]; ++ struct common_obj *common = ++ &(channel->common[VPFE_VIDEO_INDEX]); ++ struct vpfe_capture_input *vpfe_inputs = channel->video.input; ++ char *new_dec_name; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_S_INPUT\n"); ++ if (index > vpfe_inputs->num_inputs) { ++ v4l2_err(vpfe_dev->driver, "input index exceeds limit\n"); ++ return ret; ++ } ++ ++ if (!vpfe_inputs->inputs[index].input.name[0]) { ++ v4l2_err(vpfe_dev->driver, "input index exceeds limit\n"); ++ return ret; ++ } ++ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ /* If streaming is started return device busy ++ * error ++ */ ++ if (common->started) { ++ v4l2_err(vpfe_dev->driver, "Streaming is on\n"); ++ ret = -EBUSY; ++ goto lock_out; ++ } ++ new_dec_name = vpfe_inputs->inputs[index].dec_name; ++ /* switch in new decoder to be active */ ++ if (strcmp(new_dec_name, curr_dec->name)) { ++ for (i = 0; i < VPFE_CAPTURE_NUM_DECODERS; i++) { ++ if (channel->decoder[i] && ++ !strcmp(new_dec_name, ++ channel->decoder[i]->name)) { ++ new_dec = channel->decoder[i]; ++ channel->current_decoder = i; ++ /* Deinitialize the previous decoder ++ * and power down ++ */ ++ vidioc_int_s_power(curr_dec, 0); ++ ++ ret = vidioc_int_s_power(new_dec, 1); ++ if (ret) ++ goto lock_out; ++ ret = vidioc_int_init(new_dec); ++ if (ret) ++ goto lock_out; ++ curr_dec = new_dec; ++ } ++ } ++ ++ if (i == VPFE_CAPTURE_NUM_DECODERS) ++ /* couldn't find the decoder */ ++ goto lock_out; ++ } ++ ret = 0; ++ /* Set the input in the decoder */ ++ if (vpfe_inputs->inputs[index].routing_supported) ++ ret = vidioc_int_s_video_routing(curr_dec, ++ &vpfe_inputs->inputs[index].route); ++ ++ if (ret) { ++ v4l2_err(vpfe_dev->driver, ++ "vpfe_doioctl:error in setting input in decoder \n"); ++ ret = -EINVAL; ++ goto lock_out; ++ } ++ ++ vpfe_inputs->current_input = index; ++ ret = vpfe_set_hw_if_type(channel); ++ if (ret) ++ goto lock_out; ++ ++ ret = vpfe_config_default_format(channel); ++ if (ret) ++ goto lock_out; ++ ++ /* Detect default standard */ ++ ret = vidioc_int_querystd(curr_dec, &std_id); ++ if (!ret) ++ ret = vpfe_get_stdinfo(channel, &std_id); ++ ++ if (ret) ++ goto lock_out; ++ ++ vpfe_config_format(channel); ++lock_out: ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = ++ &(channel->common[VPFE_VIDEO_INDEX]); ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto lock_out; ++ /* Call querystd function of decoder device */ ++ ret = vidioc_int_querystd(dec, std_id); ++ /* Set format based on the standard selected */ ++ if (!ret) ++ ret = vpfe_get_stdinfo(channel, std_id); ++ vpfe_config_format(channel); ++lock_out: ++ mutex_unlock(&common->lock); ++ return ret; ++} ++ ++static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = ++ &(channel->common[VPFE_VIDEO_INDEX]); ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_S_STD\n"); ++ ++ /* If streaming is started, return device ++ busy error */ ++ if (common->started) { ++ v4l2_err(vpfe_dev->driver, "streaming is started\n"); ++ ret = -EBUSY; ++ goto out; ++ } ++ /* Call decoder driver function to set the ++ standard */ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ ret = vidioc_int_s_std(dec, std_id); ++ ++ /* If it returns error, return error */ ++ if (!ret) ++ ret = vpfe_get_stdinfo(channel, std_id); ++ ++ if (!ret) ++ vpfe_config_format(channel); ++out: ++ mutex_unlock(&common->lock); ++ return ret; ++} ++ ++static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ int ret; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_G_STD\n"); ++ ret = vidioc_int_querystd(dec, std_id); ++ if (ret) ++ goto out; ++ ++ ret = vpfe_get_stdinfo(channel, std_id); ++ if (!ret) ++ vpfe_config_format(channel); ++out: ++ return ret; ++} ++/* ++ * Videobuf operations ++ */ ++static int vpfe_videobuf_setup(struct videobuf_queue *vq, ++ unsigned int *count, ++ unsigned int *size) ++{ ++ /* Get the file handle object and channel object */ ++ struct vpfe_fh *fh = vq->priv_data; ++ struct channel_obj *channel = fh->channel; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_buffer_setup>\n"); ++ *size = config_params.channel_bufsize[channel->channel_id]; ++ ++ if (*count < config_params.min_numbuffers) ++ *count = config_params.min_numbuffers; ++ v4l2_dbg(1, debug, vpfe_dev->driver, ++ "count=%d, size=%d\n", *count, *size); ++ return 0; ++} ++ ++static int vpfe_videobuf_prepare(struct videobuf_queue *vq, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ int ret = 0; ++ /* Get the file handle object and channel object */ ++ struct vpfe_fh *fh = vq->priv_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common; ++ unsigned long addr; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_buffer_prepare>\n"); ++ ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ if (V4L2_MEMORY_USERPTR == common->memory) { ++ /* we don't support user ptr IO */ ++ v4l2_dbg(1, debug, vpfe_dev->driver, ++ "<vpfe_buffer_prepare: USERPTR IO" ++ " not supported>\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* If buffer is not initialized, initialize it */ ++ if (VIDEOBUF_NEEDS_INIT == vb->state) { ++ vb->width = common->width; ++ vb->height = common->height; ++ vb->size = vb->width * vb->height * 2; ++ vb->field = field; ++ } ++ addr = videobuf_to_dma_contig(vb); ++ if (vq->streaming) { ++ if (!ISALIGNED(addr)) { ++ v4l2_err(vpfe_dev->driver, "buffer_prepare:offset is" ++ "not aligned to 32 bytes\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ } ++ vb->state = VIDEOBUF_PREPARED; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_buffer_prepare>\n"); ++out: ++ return ret; ++} ++ ++static void vpfe_videobuf_queue(struct videobuf_queue *vq, ++ struct videobuf_buffer *vb) ++{ ++ /* Get the file handle object and channel object */ ++ struct vpfe_fh *fh = vq->priv_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_buffer_queue>\n"); ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ /* add the buffer to the DMA queue */ ++ list_add_tail(&vb->queue, &common->dma_queue); ++ /* Change state of the buffer */ ++ vb->state = VIDEOBUF_QUEUED; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_buffer_queue>\n"); ++} ++ ++static void vpfe_videobuf_release(struct videobuf_queue *vq, ++ struct videobuf_buffer *vb) ++{ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "vpfe_videobuf_release\n"); ++ videobuf_dma_contig_free(vq, vb); ++ vb->state = VIDEOBUF_NEEDS_INIT; ++} ++ ++static struct videobuf_queue_ops vpfe_videobuf_qops = { ++ .buf_setup = vpfe_videobuf_setup, ++ .buf_prepare = vpfe_videobuf_prepare, ++ .buf_queue = vpfe_videobuf_queue, ++ .buf_release = vpfe_videobuf_release, ++}; ++ ++static int vpfe_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *p) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ enum v4l2_field field; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_buffer_queue>\n"); ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "\nEnd of VIDIOC_REQBUFS ioctl"); ++ ++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { ++ ret = -EINVAL; ++ goto out; ++ } ++ if (common->io_usrs != 0) { ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ ++ if (common->fmt.fmt.pix.field != V4L2_FIELD_ANY) ++ field = common->fmt.fmt.pix.field; ++ else if (channel->vpfe_if == VPFE_RAW_BAYER) ++ field = V4L2_FIELD_NONE; ++ else ++ field = V4L2_FIELD_INTERLACED; ++ ++ videobuf_queue_dma_contig_init(&common->buffer_queue, ++ &vpfe_videobuf_qops, ++ NULL, ++ &common->irqlock, ++ p->type, ++ field, ++ sizeof(struct videobuf_buffer), ++ fh); ++ ++ fh->io_allowed[VPFE_VIDEO_INDEX] = 1; ++ common->io_usrs = 1; ++ INIT_LIST_HEAD(&common->dma_queue); ++ ret = videobuf_reqbufs(&common->buffer_queue, p); ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++static int vpfe_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *p) ++{ ++ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ int ret = 0; ++ u8 buf_type_index = 0; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_QUERYBUF\n"); ++ buf_type_index = VPFE_VIDEO_INDEX; ++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { ++ v4l2_err(vpfe_dev->driver, ++ "VIDIOC_QUERYBUF:Invalid buf type\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ common = &(channel->common[buf_type_index]); ++ if (p->memory != V4L2_MEMORY_MMAP) { ++ v4l2_err(vpfe_dev->driver, ++ "VIDIOC_QUERYBUF:Invalid memory\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ /* Call videobuf_querybuf to get information */ ++ return videobuf_querybuf(&common->buffer_queue, p); ++out: ++ return ret; ++} ++ ++static int vpfe_qbuf(struct file *file, void *priv, ++ struct v4l2_buffer *p) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ int buf_type_index, ret = 0; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_QBUF\n"); ++ buf_type_index = VPFE_VIDEO_INDEX; ++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { ++ v4l2_err(vpfe_dev->driver, "VIDIOC_QBUF:Invalid buf type\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ common = &(channel->common[buf_type_index]); ++ ++ /* If this file handle is not allowed to do IO, ++ * return error ++ */ ++ if (!fh->io_allowed[buf_type_index]) { ++ v4l2_err(vpfe_dev->driver, "fh->io_allowed\n"); ++ ret = -EACCES; ++ goto out; ++ } ++ return videobuf_qbuf(&common->buffer_queue, p); ++out: ++ return ret; ++} ++static int vpfe_dqbuf(struct file *file, void *priv, ++ struct v4l2_buffer *p) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ int buf_type_index = 0, ret = 0; ++ buf_type_index = VPFE_VIDEO_INDEX; ++ common = &(channel->common[buf_type_index]); ++ ++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { ++ v4l2_err(vpfe_dev->driver, "VIDIOC_DQBUF:Invalid buf type\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ if (file->f_flags & O_NONBLOCK) ++ ret = videobuf_dqbuf(&common->buffer_queue, p, 1); ++ else ++ ret = videobuf_dqbuf(&common->buffer_queue, p, 0); ++out: ++ return ret; ++} ++ ++/* vpfe_calculate_offsets : This function calculates buffers offset ++ * for top and bottom field ++ */ ++static void vpfe_calculate_offsets(struct channel_obj *channel) ++{ ++ struct common_obj *common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ struct v4l2_rect image_win; ++ ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_calculate_offsets>\n"); ++ ++ common->field_off = 0; ++ ccdc_hw_dev.get_image_window(&image_win); ++ common->field_off = (image_win.height - 2) * image_win.width; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_calculate_offsets>\n"); ++} ++ ++static int vpfe_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type i) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ int buf_type_index = VPFE_VIDEO_INDEX; ++ unsigned long addr; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_STREAMON\n"); ++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != i) { ++ v4l2_err(vpfe_dev->driver, ++ "VIDIOC_STREAMON:Invalid buf type\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ common = &(channel->common[buf_type_index]); ++ /* If file handle is not allowed IO, ++ * return error ++ */ ++ if (!fh->io_allowed[buf_type_index]) { ++ v4l2_err(vpfe_dev->driver, "fh->io_allowed\n"); ++ ret = -EACCES; ++ goto out; ++ } ++ /* If Streaming is already started, ++ * return error ++ */ ++ if (common->started) { ++ v4l2_err(vpfe_dev->driver, "channel->started\n"); ++ ret = -EBUSY; ++ goto out; ++ } ++ /* Call videobuf_streamon to start streaming ++ * in videobuf ++ */ ++ ret = videobuf_streamon(&common->buffer_queue); ++ if (ret) ++ goto out; ++ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ /* If buffer queue is empty, return error */ ++ if (list_empty(&common->dma_queue)) { ++ v4l2_err(vpfe_dev->driver, "buffer queue is empty\n"); ++ ret = -EIO; ++ goto lock_out; ++ } ++ /* Get the next frame from the buffer queue */ ++ common->nextFrm = common->curFrm = ++ list_entry(common->dma_queue.next, ++ struct videobuf_buffer, queue); ++ /* Remove buffer from the buffer queue */ ++ list_del(&common->curFrm->queue); ++ /* Mark state of the current frame to active */ ++ common->curFrm->state = VIDEOBUF_ACTIVE; ++ /* Initialize field_id and started member */ ++ channel->field_id = 0; ++ common->started = 1; ++ ++ addr = videobuf_to_dma_contig(common->curFrm); ++ ++ /* Calculate field offset */ ++ vpfe_calculate_offsets(channel); ++ ++ if (vpfe_attach_irq(channel) < 0) { ++ v4l2_err(vpfe_dev->driver, ++ "Error in attaching interrupt handle\n"); ++ ret = -EFAULT; ++ goto lock_out; ++ } ++ ++ ccdc_hw_dev.configure(); ++ ccdc_hw_dev.setfbaddr((unsigned long)(addr)); ++ ccdc_hw_dev.enable(1); ++ if (ccdc_hw_dev.enable_out_to_sdram) ++ ccdc_hw_dev.enable_out_to_sdram(1); ++lock_out: ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++static int vpfe_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type i) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ int buf_type_index = VPFE_VIDEO_INDEX, ret = 0; ++ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != i) { ++ v4l2_err(vpfe_dev->driver, ++ "VIDIOC_STREAMOFF:Invalid buf type\n"); ++ return -EINVAL; ++ } ++ common = &(channel->common[buf_type_index]); ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_STREAMOFF\n"); ++ /* If io is allowed for this file handle, ++ * return error ++ */ ++ if (!fh->io_allowed[buf_type_index]) { ++ v4l2_err(vpfe_dev->driver, "fh->io_allowed\n"); ++ ret = -EACCES; ++ goto out; ++ } ++ /* If streaming is not started, return error */ ++ if (!common->started) { ++ v4l2_err(vpfe_dev->driver, "channel->started\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ common->started = 0; ++ ccdc_hw_dev.enable(0); ++ if (ccdc_hw_dev.enable_out_to_sdram) ++ ccdc_hw_dev.enable_out_to_sdram(0); ++ if (vpfe_detach_irq(channel) < 0) { ++ v4l2_err(vpfe_dev->driver, ++ "Error in detaching interrupt handler\n"); ++ mutex_unlock(&common->lock); ++ ret = -EFAULT; ++ goto lock_out; ++ } ++ ret = videobuf_streamoff(&common->buffer_queue); ++lock_out: ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++static int vpfe_queryctrl(struct file *file, void *priv, ++ struct v4l2_queryctrl *qc) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_QUERYCTRL\n"); ++ /* Call queryctrl function of decoder device */ ++ return vidioc_int_queryctrl(dec, qc); ++} ++ ++static int vpfe_g_ctrl(struct file *file, void *priv, ++ struct v4l2_control *ctrl) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ struct common_obj *common = ++ &(channel->common[VPFE_VIDEO_INDEX]); ++ int ret = 0; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_G_CTRL\n"); ++ /* Call getcontrol function of decoder device */ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ return ret; ++ ret = vidioc_int_g_ctrl(dec, ctrl); ++ mutex_unlock(&common->lock); ++ return ret; ++} ++ ++static int vpfe_s_ctrl(struct file *file, void *priv, ++ struct v4l2_control *ctrl) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = ++ &(channel->common[VPFE_VIDEO_INDEX]); ++ struct v4l2_int_device *dec = ++ channel->decoder[channel->current_decoder]; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "VIDIOC_S_CTRL\n"); ++ /* Call setcontrol function of decoder device */ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ return ret; ++ ret = vidioc_int_s_ctrl(dec, ctrl); ++ mutex_unlock(&common->lock); ++ return ret; ++} ++ ++static int vpfe_cropcap(struct file *file, void *priv, ++ struct v4l2_cropcap *crop) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct video_obj *vid_ch = NULL; ++ vid_ch = &(channel->video); ++ ++ if (vid_ch->index > vpfe_max_standards) ++ return -EINVAL; ++ memset(crop, 0, sizeof(struct v4l2_cropcap)); ++ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ crop->bounds.width = crop->defrect.width = ++ vpfe_standards[vid_ch->index].width; ++ crop->bounds.height = crop->defrect.height = ++ vpfe_standards[vid_ch->index].height; ++ crop->pixelaspect = vpfe_standards[vid_ch->index].pixelaspect; ++ return 0; ++} ++ ++static int vpfe_g_crop(struct file *file, void *priv, ++ struct v4l2_crop *crop) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ v4l2_dbg(1, debug, vpfe_dev->driver, "\nStarting VIDIOC_G_CROP ioctl"); ++ crop->c = common->crop; ++ return 0; ++} ++ ++static int vpfe_s_crop(struct file *file, void *priv, ++ struct v4l2_crop *crop) ++{ ++ int ret = 0; ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ struct video_obj *vid_ch = NULL; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ vid_ch = &(channel->video); ++ v4l2_dbg(1, debug, vpfe_dev->driver, "\nStarting VIDIOC_S_CROP ioctl"); ++ if (common->started) { ++ /* make sure streaming is not started */ ++ v4l2_err(vpfe_dev->driver, ++ "Cannot change crop when streaming is ON\n"); ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ /* make sure parameters are valid */ ++ if ((crop->c.left + crop->c.width <= vid_ch->std_info.activepixels) && ++ (crop->c.top + crop->c.height <= vid_ch->std_info.activelines)) { ++ /* adjust the width to 16 pixel boundry */ ++ crop->c.width = ((crop->c.width + 15) & ~0xf); ++ ccdc_hw_dev.set_image_window(&crop->c); ++ common->fmt.fmt.pix.width = crop->c.width; ++ common->fmt.fmt.pix.height = crop->c.height; ++ ccdc_hw_dev.get_line_length(&common->fmt.fmt.pix.bytesperline); ++ common->fmt.fmt.pix.sizeimage = ++ common->fmt.fmt.pix. ++ bytesperline * ++ common->fmt.fmt.pix.height; ++ common->crop = crop->c; ++ } else { ++ v4l2_err(vpfe_dev->driver, "Error in S_CROP params\n"); ++ ret = -EINVAL; ++ } ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++ ++static long vpfe_param_handler(struct file *file, void *priv, ++ int cmd, void *param) ++{ ++ struct vpfe_fh *fh = file->private_data; ++ struct channel_obj *channel = fh->channel; ++ struct common_obj *common = NULL; ++ int ret = 0; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ ++ if (common->started) { ++ /* only allowed if streaming is not started */ ++ v4l2_err(vpfe_dev->driver, "channel already started\n"); ++ ret = -EBUSY; ++ goto out; ++ } ++ ret = mutex_lock_interruptible(&common->lock); ++ if (ret) ++ goto out; ++ switch (cmd) { ++ case VPFE_CMD_S_SOC_PARAMS: ++ { ++ ret = ccdc_hw_dev.setparams(param); ++ if (ret) { ++ v4l2_err(vpfe_dev->driver, ++ "Error in setting parameters" ++ " in CCDC \n"); ++ goto lock_out; ++ } ++ if (vpfe_get_image_format(&common->fmt) < 0) { ++ v4l2_err(vpfe_dev->driver, ++ "Invalid image format at CCDC \n"); ++ goto lock_out; ++ } ++ break; ++ } ++ default: ++ ret = -EINVAL; ++ } ++lock_out: ++ mutex_unlock(&common->lock); ++out: ++ return ret; ++} ++ ++ ++/* vpfe capture ioctl operations */ ++static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { ++ .vidioc_querycap = vpfe_querycap, ++ .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, ++ .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, ++ .vidioc_enum_input = vpfe_enum_input, ++ .vidioc_g_input = vpfe_g_input, ++ .vidioc_s_input = vpfe_s_input, ++ .vidioc_querystd = vpfe_querystd, ++ .vidioc_s_std = vpfe_s_std, ++ .vidioc_g_std = vpfe_g_std, ++ .vidioc_reqbufs = vpfe_reqbufs, ++ .vidioc_querybuf = vpfe_querybuf, ++ .vidioc_qbuf = vpfe_qbuf, ++ .vidioc_dqbuf = vpfe_dqbuf, ++ .vidioc_streamon = vpfe_streamon, ++ .vidioc_streamoff = vpfe_streamoff, ++ .vidioc_queryctrl = vpfe_queryctrl, ++ .vidioc_g_ctrl = vpfe_g_ctrl, ++ .vidioc_s_ctrl = vpfe_s_ctrl, ++ .vidioc_cropcap = vpfe_cropcap, ++ .vidioc_g_crop = vpfe_g_crop, ++ .vidioc_s_crop = vpfe_s_crop, ++ .vidioc_default = vpfe_param_handler, ++}; ++ ++/* vpfe_probe : This function creates device entries by register ++ * itself to the V4L2 driver and initializes fields of each ++ * channel objects ++ */ ++static __init int vpfe_probe(struct platform_device *device) ++{ ++ struct common_obj *common = NULL; ++ int err = -ENOMEM, index = 0; ++ struct video_device *vfd = NULL; ++ struct channel_obj *channel = NULL; ++ struct video_obj *vid_ch = NULL; ++ struct resource *res1, *res2; ++ void *__iomem mem1; ++ void *__iomem mem2; ++ ++ vpfe_dev = &device->dev; ++ ++ /* Get the pointer to the channel object */ ++ channel = vpfe_obj.dev[0]; ++ /* Allocate memory for video device */ ++ vfd = video_device_alloc(); ++ if (ISNULL(vfd)) { ++ v4l2_err(vpfe_dev->driver, ++ "Unable to alloc video device\n"); ++ return err; ++ } ++ ++ /* Initialize field of video device */ ++ vfd->release = video_device_release; ++ vfd->current_norm = V4L2_STD_UNKNOWN; ++ vfd->fops = &vpfe_fops; ++ vfd->ioctl_ops = &vpfe_ioctl_ops; ++ vfd->minor = -1; ++ vfd->tvnorms = V4L2_STD_UNKNOWN, ++ vfd->dev = device->dev; ++ snprintf(vfd->name, sizeof(vfd->name), ++ "%s_V%d.%d.%d", ++ CAPTURE_DRV_NAME, ++ (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, ++ (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, ++ (VPFE_CAPTURE_VERSION_CODE) & 0xff); ++ /* Set video_dev to the video device */ ++ channel->video_dev = vfd; ++ ++ channel->usrs = 0; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ common->io_usrs = 0; ++ common->started = 0; ++ spin_lock_init(&common->irqlock); ++ common->numbuffers = 0; ++ common->field_off = 0; ++ common->curFrm = common->nextFrm = NULL; ++ memset(&common->fmt, 0, sizeof(struct v4l2_format)); ++ channel->initialized = 0; ++ channel->channel_id = 0; ++ vid_ch = &(channel->video); ++ vid_ch->input = device->dev.platform_data; ++ if (!vid_ch->input) { ++ v4l2_err(vpfe_dev->driver, ++ "Unable to get inputs to vpfe\n"); ++ err = -ENOENT; ++ goto probe_out_release; ++ } ++ vid_ch->index = 0; ++ channel->irq_type = VPFE_NO_IRQ; ++ /* Get VINT0 irq resource */ ++ res1 = platform_get_resource(device, IORESOURCE_IRQ, 0); ++ if (!res1) { ++ err = -ENOENT; ++ v4l2_err(vpfe_dev->driver, "Unable to get interrupt for VINT0"); ++ goto probe_out_release; ++ } ++ channel->ccdc_irq0 = res1->start; ++ ++ /* Get VINT1 irq resource */ ++ res1 = platform_get_resource(device, ++ IORESOURCE_IRQ, 1); ++ if (!res1) { ++ err = -ENOENT; ++ v4l2_err(vpfe_dev->driver, ++ "Unable to get interrupt for VINT1"); ++ goto probe_out_release; ++ } ++ channel->ccdc_irq1 = res1->start; ++ channel->res1 = platform_get_resource(device, IORESOURCE_MEM, 0); ++ channel->res2 = platform_get_resource(device, IORESOURCE_MEM, 1); ++ if (!channel->res1 || !channel->res2) { ++ v4l2_err(vpfe_dev->driver, ++ "Unable to get register address map\n"); ++ err = -ENOENT; ++ goto probe_out_release; ++ } ++ res1 = (struct resource *)channel->res1; ++ res2 = (struct resource *)channel->res2; ++ if (!request_mem_region(res1->start, res1->end - res1->start + 1, ++ vpfe_dev->driver->name)) { ++ err = -ENXIO; ++ v4l2_err(vpfe_dev->driver, ++ "Failed request_mem_region for ccdc base\n"); ++ goto probe_out_release; ++ } ++ ++ mem1 = ioremap_nocache(res1->start, res1->end - res1->start + 1); ++ if (!mem1) { ++ v4l2_err(vpfe_dev->driver, "Unable to ioremap ccdc address\n"); ++ goto probe_out_release_mem1; ++ } ++ ++ ccdc_hw_dev.set_ccdc_base(mem1, res1->end - res1->start + 1); ++ ++ if (!request_mem_region(res2->start, res2->end - res2->start + 1, ++ vpfe_dev->driver->name)) { ++ err = -ENXIO; ++ v4l2_err(vpfe_dev->driver, ++ "Failed request_mem_region for" ++ " vpss base\n"); ++ goto probe_out_unmap1; ++ } ++ ++ mem2 = ioremap_nocache(res2->start, res2->end - res2->start + 1); ++ if (!mem2) { ++ v4l2_err(vpfe_dev->driver, "Unable to ioremap vpss address\n"); ++ goto probe_out_release_mem2; ++ } ++ ++ ccdc_hw_dev.set_vpss_base(mem2, res2->end - res2->start + 1); ++ ++ err = request_irq(channel->ccdc_irq0, vpfe_isr, IRQF_DISABLED, ++ "vpfe_capture0", (void *)&vpfe_obj); ++ ++ if (0 != err) { ++ v4l2_err(vpfe_dev->driver, ++ "Unable to request interrupt\n"); ++ goto probe_out_unmap2; ++ } ++ ++ /* Initialize field of the channel objects */ ++ channel->usrs = common->io_usrs = 0; ++ common->started = channel->initialized = 0; ++ channel->channel_id = 0; ++ common->numbuffers = config_params.numbuffers[channel->channel_id]; ++ channel->numdecoders = 0; ++ channel->current_decoder = 0; ++ for (index = 0; index < VPFE_CAPTURE_NUM_DECODERS; index++) ++ channel->decoder[index] = NULL; ++ ++ /* Initialize prio member of channel object */ ++ v4l2_prio_init(&channel->prio); ++ ++ /* register video device */ ++ v4l2_dbg(1, debug, vpfe_dev->driver, ++ "trying to register vpfe device.\n"); ++ v4l2_dbg(1, debug, vpfe_dev->driver, ++ "channel=%x,channel->video_dev=%x\n", ++ (int)channel, (int)&channel->video_dev); ++ channel->common[VPFE_VIDEO_INDEX].fmt.type = ++ V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ err = video_register_device(channel->video_dev, ++ VFL_TYPE_GRABBER, vpfe_nr[0]); ++ ++ dev_notice(vpfe_dev, "video device registered\n"); ++ if (err) { ++ v4l2_err(vpfe_dev->driver, ++ "Unable to register video device.\n"); ++ goto probe_out_release_irq; ++ } ++ ++ vpfe_capture.priv = channel; ++ err = v4l2_int_device_register(&vpfe_capture); ++ if (err) { ++ v4l2_err(vpfe_dev->driver, ++ "Unable to register int master device.\n"); ++ goto probe_out; ++ } ++ dev_notice(vpfe_dev, "v4l2 int master registered\n"); ++ mutex_init(&common->lock); ++ return 0; ++ ++probe_out: ++ /* Get the pointer to the channel object */ ++ channel = vpfe_obj.dev[0]; ++ /* Unregister video device */ ++ video_unregister_device(channel->video_dev); ++ v4l2_int_device_unregister(&vpfe_capture); ++ ++probe_out_release_irq: ++ free_irq(channel->ccdc_irq0, (void *)&vpfe_obj); ++probe_out_unmap2: ++ iounmap(mem2); ++probe_out_unmap1: ++ iounmap(mem1); ++probe_out_release_mem1: ++ release_mem_region(res1->start, res1->end - ++ res1->start + 1); ++probe_out_release_mem2: ++ release_mem_region(res2->start, ++ res2->end - ++ res2->start + 1); ++probe_out_release: ++ video_device_release(channel->video_dev); ++ channel->video_dev = NULL; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_probe>\n"); ++ return err; ++} ++ ++/* vpfe_remove : It un-register channels from V4L2 driver ++ */ ++static int vpfe_remove(struct platform_device *device) ++{ ++ struct channel_obj *channel; ++ struct common_obj *common = NULL; ++ struct resource *res; ++ v4l2_dbg(1, debug, vpfe_dev->driver, "<vpfe_remove>\n"); ++ ++ /* un-register device */ ++ channel = vpfe_obj.dev[0]; ++ common = &(channel->common[VPFE_VIDEO_INDEX]); ++ free_irq(channel->ccdc_irq0, (void *)&vpfe_obj); ++ /* Unregister video device */ ++ video_unregister_device(channel->video_dev); ++ video_device_release(channel->video_dev); ++ v4l2_int_device_unregister(&vpfe_capture); ++ channel->video_dev = NULL; ++ res = (struct resource *)channel->res1; ++ release_mem_region(res->start, res->end - res->start + 1); ++ res = (struct resource *)channel->res2; ++ release_mem_region(res->start, res->end - res->start + 1); ++ iounmap(ccdc_hw_dev.get_ccdc_base()); ++ iounmap(ccdc_hw_dev.get_vpss_base()); ++ v4l2_dbg(1, debug, vpfe_dev->driver, "</vpfe_remove>\n"); ++ return 0; ++} ++ ++static int ++vpfe_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ /* add suspend code here later */ ++ return 0; ++} ++ ++static int ++vpfe_resume(struct platform_device *dev) ++{ ++ /* add resume code here later */ ++ return 0; ++} ++ ++static struct platform_driver vpfe_driver = { ++ .driver = { ++ .name = CAPTURE_DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = vpfe_probe, ++ .remove = __devexit_p(vpfe_remove), ++ .suspend = vpfe_suspend, ++ .resume = vpfe_resume, ++}; ++ ++static __init int vpfe_init(void) ++{ ++ int err = 0; ++ ++ /* Default number of buffers should be 3 */ ++ if ((ch0_numbuffers > 0) && ++ (ch0_numbuffers < config_params.min_numbuffers)) ++ ch0_numbuffers = config_params.min_numbuffers; ++ ++ /* Set buffer size to min buffers size if invalid buffer size is ++ * given ++ */ ++ if (ch0_bufsize < config_params.min_bufsize[VPFE_CHANNEL0_VIDEO]) ++ ch0_bufsize = ++ config_params.min_bufsize[VPFE_CHANNEL0_VIDEO]; ++ ++ config_params.numbuffers[VPFE_CHANNEL0_VIDEO] = ch0_numbuffers; ++ ++ if (ch0_numbuffers) ++ config_params.channel_bufsize[VPFE_CHANNEL0_VIDEO] ++ = ch0_bufsize; ++ ++ if (ISNULL(ccdc_hw_dev.enable) || ++ ISNULL(ccdc_hw_dev.open) || ++ ISNULL(ccdc_hw_dev.set_hw_if_type) || ++ ISNULL(ccdc_hw_dev.configure) || ++ ISNULL(ccdc_hw_dev.set_buftype) || ++ ISNULL(ccdc_hw_dev.get_buftype) || ++ ISNULL(ccdc_hw_dev.enum_pix) || ++ ISNULL(ccdc_hw_dev.set_frame_format) || ++ ISNULL(ccdc_hw_dev.get_frame_format) || ++ ISNULL(ccdc_hw_dev.get_pixelformat) || ++ ISNULL(ccdc_hw_dev.set_pixelformat) || ++ ISNULL(ccdc_hw_dev.setparams) || ++ ISNULL(ccdc_hw_dev.set_image_window) || ++ ISNULL(ccdc_hw_dev.get_image_window) || ++ ISNULL(ccdc_hw_dev.get_line_length) || ++ ISNULL(ccdc_hw_dev.setfbaddr) || ++ ISNULL(ccdc_hw_dev.getfid)) { ++ printk(KERN_ERR "vpfe_init:CCDC module interface" ++ "has missing mandatory functions\n"); ++ return -ENODEV; ++ } ++ ++ /* Allocate memory for channel objects */ ++ vpfe_obj.dev[0] = kmalloc(sizeof(struct channel_obj), GFP_KERNEL); ++ /* If memory allocation fails, return error */ ++ if (!vpfe_obj.dev[0]) { ++ err = -ENOMEM; ++ printk(KERN_ERR "vpfe_init:Memory allocation failed\n"); ++ goto vpfe_init_free_channel_object; ++ } ++ ++ /* Register driver to the kernel */ ++ err = platform_driver_register(&vpfe_driver); ++ if (0 != err) ++ goto vpfe_init_free_channel_object; ++ ++ printk(KERN_NOTICE "vpfe_capture: init successful\n"); ++ return err; ++ ++vpfe_init_free_channel_object: ++ kfree(vpfe_obj.dev[0]); ++ vpfe_obj.dev[0] = NULL; ++ return err; ++} ++ ++/* vpfe_cleanup : This function un-registers device and driver ++ * to the kernel, frees requested irq handler and de-allocates memory ++ * allocated for channel objects. ++ */ ++static void vpfe_cleanup(void) ++{ ++ platform_driver_unregister(&vpfe_driver); ++ kfree(vpfe_obj.dev[0]); ++ vpfe_obj.dev[0] = NULL; ++} ++module_init(vpfe_init); ++module_exit(vpfe_cleanup); ++MODULE_AUTHOR("Texas Instruments."); ++MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/video/davinci_vpfe.c b/drivers/media/video/davinci_vpfe.c +deleted file mode 100644 +index 1128eb5..0000000 +--- a/drivers/media/video/davinci_vpfe.c ++++ /dev/null +@@ -1,1136 +0,0 @@ +-/* +- * +- * +- * Copyright (C) 2006 Texas Instruments Inc +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +-/* davinci_vpfe.c */ +- +-#include <linux/init.h> +-#include <linux/module.h> +-#include <linux/delay.h> +-#include <linux/errno.h> +-#include <linux/fs.h> +-#include <linux/kernel.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/kdev_t.h> +-#include <linux/string.h> +-#include <linux/videodev.h> +-#include <linux/wait.h> +-#include <linux/dma-mapping.h> +-#include <linux/platform_device.h> +- +-#include <asm/irq.h> +-#include <asm/page.h> +-#include <asm/io.h> +-#include <asm/dma-mapping.h> +- +-#include <media/davinci_vpfe.h> +- +-#define debug_print(x...) //printk(x) +- +-MODULE_LICENSE("GPL"); +- +-static struct v4l2_rect ntsc_bounds = VPFE_WIN_NTSC; +-static struct v4l2_rect pal_bounds = VPFE_WIN_PAL; +-static struct v4l2_fract ntsc_aspect = VPFE_PIXELASPECT_NTSC; +-static struct v4l2_fract pal_aspect = VPFE_PIXELASPECT_PAL; +-static struct v4l2_rect ntscsp_bounds = VPFE_WIN_NTSC_SP; +-static struct v4l2_rect palsp_bounds = VPFE_WIN_PAL_SP; +-static struct v4l2_fract sp_aspect = VPFE_PIXELASPECT_NTSC_SP; +- +-static vpfe_obj vpfe_device = { /* the default format is NTSC */ +- .usrs = 0, +- .io_usrs = 0, +- .std = VPFE_STD_AUTO, +- .vwin = VPFE_WIN_PAL, +- .bounds = VPFE_WIN_PAL, +- .pixelaspect = VPFE_PIXELASPECT_NTSC, +- .pixelfmt = V4L2_PIX_FMT_UYVY, +- .field = V4L2_FIELD_INTERLACED, +- .numbuffers = VPFE_DEFNUM_FBUFS, +- .ccdc_params = { +- .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, +- .frm_fmt = CCDC_FRMFMT_INTERLACED, +- .win = VPFE_WIN_PAL, +- .fid_pol = CCDC_PINPOL_POSITIVE, +- .vd_pol = CCDC_PINPOL_POSITIVE, +- .hd_pol = CCDC_PINPOL_POSITIVE, +- .bt656_enable = TRUE, +- .pix_order = CCDC_PIXORDER_CBYCRY, +- .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED +- }, +- .tvp5146_params = { +- .mode = TVP5146_MODE_AUTO, +- .amuxmode = TVP5146_AMUX_COMPOSITE, +- .enablebt656sync = TRUE +- }, +- .irqlock = SPIN_LOCK_UNLOCKED +-}; +- +-struct v4l2_capability vpfe_drvcap = { +- .driver = "vpfe driver", +- .card = "DaVinci EVM", +- .bus_info = "Platform", +- .version = VPFE_VERSION_CODE, +- .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING +-}; +- +-static int sense_std(v4l2_std_id* std_id) +-{ +- v4l2_std_id id = 0; +- tvp5146_mode mode; +- int ret; +- ret = tvp5146_ctrl(TVP5146_GET_STD, &mode); +- if(ret < 0) +- return ret; +- switch (mode & 0x7) { +- case TVP5146_MODE_NTSC: +- id = V4L2_STD_NTSC; +- break; +- case TVP5146_MODE_PAL: +- id = V4L2_STD_PAL; +- break; +- case TVP5146_MODE_PAL_M: +- id = V4L2_STD_PAL_M; +- break; +- case TVP5146_MODE_PAL_CN: +- id = V4L2_STD_PAL_N; +- break; +- case TVP5146_MODE_SECAM: +- id = V4L2_STD_SECAM; +- break; +- case TVP5146_MODE_PAL_60: +- id = V4L2_STD_PAL_60; +- break; +- } +- if (mode & 0x8) { /* square pixel mode */ +- id <<= 32; +- } +- if (mode == TVP5146_MODE_AUTO) { +- id = VPFE_STD_AUTO; /* auto-detection for all other modes */ +- } else if (mode == TVP5146_MODE_AUTO_SQP) { +- id = VPFE_STD_AUTO_SQP; +- } +- if(id == 0) +- return -EINVAL; +- *std_id = id; +- return 0; +-} +- +-static irqreturn_t vpfe_isr(int irq, void *dev_id) +-{ +- vpfe_obj *vpfe = &vpfe_device; +- int fid; +- +- /* check which field we are in hardware */ +- fid = ccdc_getfid(); +- vpfe->field_id ^= 1; /* switch the software maintained field id */ +- debug_print(KERN_INFO "field id = %x:%x.\n", fid, vpfe->field_id); +- if (fid == vpfe->field_id) { /* we are in-sync here, continue */ +- if (fid == 0) { +- /* One frame is just being captured. If the next frame +- is available, release the current frame and move on */ +- if (vpfe->curFrm != vpfe->nextFrm) { +- vpfe->curFrm->state = STATE_DONE; +- wake_up_interruptible(&vpfe->curFrm->done); +- vpfe->curFrm = vpfe->nextFrm; +- } +- /* based on whether the two fields are stored interleavely */ +- /* or separately in memory, reconfigure the CCDC memory address */ +- if (vpfe->field == V4L2_FIELD_SEQ_TB) { +- u32 addr = +- vpfe->curFrm->boff + vpfe->field_offset; +- ccdc_setfbaddr((unsigned long)addr); +- } +- } else if (fid == 1) { +- /* if one field is just being captured */ +- /* configure the next frame */ +- /* get the next frame from the empty queue */ +- /* if no frame is available, hold on to the current buffer */ +- if (!list_empty(&vpfe->dma_queue) +- && vpfe->curFrm == vpfe->nextFrm) { +- vpfe->nextFrm = list_entry(vpfe->dma_queue.next, +- struct videobuf_buffer, queue); +- list_del(&vpfe->nextFrm->queue); +- vpfe->nextFrm->state = STATE_ACTIVE; +- ccdc_setfbaddr( +- (unsigned long)vpfe->nextFrm->boff); +- } +- if (vpfe->mode_changed) { +- ccdc_setwin(&vpfe->ccdc_params); +- /* update the field offset */ +- vpfe->field_offset = +- (vpfe->vwin.height - 2) * vpfe->vwin.width; +- vpfe->mode_changed = FALSE; +- } +- } +- } else if (fid == 0) { +- /* recover from any hardware out-of-sync due to */ +- /* possible switch of video source */ +- /* for fid == 0, sync up the two fids */ +- /* for fid == 1, no action, one bad frame will */ +- /* go out, but it is not a big deal */ +- vpfe->field_id = fid; +- } +- debug_print(KERN_INFO "interrupt returned.\n"); +- return IRQ_RETVAL(1); +-} +- +-/* this is the callback function called from videobuf_qbuf() function */ +-/* the buffer is prepared and queued into the dma queue */ +-static int buffer_prepare(struct videobuf_queue *q, +- struct videobuf_buffer *vb, +- enum v4l2_field field) +-{ +- vpfe_obj *vpfe = &vpfe_device; +- +- +- if (vb->state == STATE_NEEDS_INIT) { +- vb->width = vpfe->vwin.width; +- vb->height = vpfe->vwin.height; +- vb->size = VPFE_MAX_FBUF_SIZE; +- vb->field = field; +- } +- vb->state = STATE_PREPARED; +- +- return 0; +- +-} +-static void +-buffer_config(struct videobuf_queue *q, unsigned int count) +-{ +- vpfe_obj *vpfe = &vpfe_device; +- int i; +- for(i = 0; i < count; i++) { +- q->bufs[i]->boff = virt_to_phys(vpfe->fbuffers[i]); +- debug_print(KERN_INFO "buffer address: %x\n", q->bufs[i]->boff); +- } +-} +- +-static int +-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +-{ +- vpfe_obj *vpfe = &vpfe_device; +- int i; +- *size = VPFE_MAX_FBUF_SIZE; +- +- +- for (i = VPFE_DEFNUM_FBUFS; i < *count; i++) { +- u32 size = PAGE_SIZE << VPFE_MAX_FBUF_ORDER; +- void *mem = (void *)__get_free_pages(GFP_KERNEL |GFP_DMA, +- VPFE_MAX_FBUF_ORDER); +- if (mem) { +- unsigned long adr = (unsigned long)mem; +- while (size > 0) { +- /* make sure the frame buffers are never +- swapped out of memory */ +- SetPageReserved(virt_to_page(adr)); +- adr += PAGE_SIZE; +- size -= PAGE_SIZE; +- } +- vpfe->fbuffers[i] = mem; +- } else { +- break; +- } +- } +- *count = vpfe->numbuffers = i; +- +- return 0; +-} +- +-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +-{ +- vpfe_obj *vpfe = &vpfe_device; +- /* add the buffer to the DMA queue */ +- list_add_tail(&vb->queue, &vpfe->dma_queue); +- vb->state = STATE_QUEUED; +-} +- +-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +-{ +- /* free the buffer if it is not one of the 3 allocated at initializaiton time */ +- if(vb->i < vpfe_device.numbuffers +- && vb->i >= VPFE_DEFNUM_FBUFS +- && vpfe_device.fbuffers[vb->i]){ +- free_pages((unsigned long)vpfe_device.fbuffers[vb->i], +- VPFE_MAX_FBUF_ORDER); +- vpfe_device.fbuffers[vb->i] = NULL; +- } +-} +- +- +-static struct videobuf_queue_ops video_qops = { +- .buf_setup = buffer_setup, +- .buf_prepare = buffer_prepare, +- .buf_queue = buffer_queue, +- .buf_release = buffer_release, +- .buf_config = buffer_config, +-}; +- +- +- +- +-static int vpfe_doioctl(struct inode *inode, struct file *file, +- unsigned int cmd, void *arg) +-{ +- vpfe_obj *vpfe = &vpfe_device; +- vpfe_fh *fh = file->private_data; +- int ret = 0; +- switch (cmd) { +- case VIDIOC_S_CTRL: +- case VIDIOC_S_FMT: +- case VIDIOC_S_STD: +- case VIDIOC_S_CROP: +- ret = v4l2_prio_check(&vpfe->prio, &fh->prio); +- if (0 != ret) { +- return ret; +- } +- break; +- } +- +- switch (cmd) { +- case VIDIOC_QUERYCAP: +- { +- struct v4l2_capability *cap = +- (struct v4l2_capability *)arg; +- memset(cap, 0, sizeof(*cap)); +- *cap = vpfe_drvcap; +- break; +- } +- case VIDIOC_ENUM_FMT: +- { +- struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *)arg; +- u32 index = fmt->index; +- memset(fmt, 0, sizeof(*fmt)); +- fmt->index = index; +- if (index == 0) { +- /* only yuv4:2:2 format is supported at this point */ +- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +- strcpy(fmt->description, +- "YCbCr4:2:2 Interleaved UYUV"); +- fmt->pixelformat = V4L2_PIX_FMT_UYVY; +- } else if (index == 1) { +- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +- strcpy(fmt->description, +- "YCbCr4:2:2 Interleaved YUYV"); +- fmt->pixelformat = V4L2_PIX_FMT_YUYV; +- } else { +- ret = -EINVAL; +- } +- break; +- } +- case VIDIOC_G_FMT: +- { +- struct v4l2_format *fmt = (struct v4l2_format *)arg; +- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +- ret = -EINVAL; +- } else { +- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; +- down_interruptible(&vpfe->lock); +- pixfmt->width = vpfe->vwin.width; +- pixfmt->height = vpfe->vwin.height; +- pixfmt->field = vpfe->field; +- pixfmt->pixelformat = vpfe->pixelfmt; +- pixfmt->bytesperline = pixfmt->width * 2; +- pixfmt->sizeimage = +- pixfmt->bytesperline * pixfmt->height; +- pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; +- up(&vpfe->lock); +- } +- break; +- } +- case VIDIOC_S_FMT: +- { +- struct v4l2_format *fmt = (struct v4l2_format *)arg; +- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; +- ccdc_params_ycbcr *params = &vpfe->ccdc_params; +- if (vpfe->started) { /* make sure streaming is not started */ +- ret = -EBUSY; +- break; +- } +- +- down_interruptible(&vpfe->lock); +- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +- ret = -EINVAL; +- up(&vpfe->lock); +- break; +- } +- if ((pixfmt->width + vpfe->vwin.left <= +- vpfe->bounds.width) +- & (pixfmt->height + vpfe->vwin.top <= +- vpfe->bounds.height)) { +- /* this is the case when no scaling is supported */ +- /* crop window is directed modified */ +- vpfe->vwin.height = pixfmt->height; +- vpfe->vwin.width = pixfmt->width; +- params->win.width = pixfmt->width; +- params->win.height = pixfmt->height; +- } else { +- ret = -EINVAL; +- up(&vpfe->lock); +- break; +- } +- /* setup the CCDC parameters accordingly */ +- if (pixfmt->pixelformat == V4L2_PIX_FMT_YUYV) { +- params->pix_order = CCDC_PIXORDER_YCBYCR; +- vpfe->pixelfmt = pixfmt->pixelformat; +- } else if (pixfmt->pixelformat == V4L2_PIX_FMT_UYVY) { +- params->pix_order = CCDC_PIXORDER_CBYCRY; +- vpfe->pixelfmt = pixfmt->pixelformat; +- } else { +- ret = -EINVAL; /* not supported format */ +- up(&vpfe->lock); +- break; +- } +- if (pixfmt->field == V4L2_FIELD_NONE +- || pixfmt->field == V4L2_FIELD_INTERLACED) { +- params->buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED; +- vpfe->field = pixfmt->field; +- } else if (pixfmt->field == V4L2_FIELD_SEQ_TB) { +- params->buf_type = CCDC_BUFTYPE_FLD_SEPARATED; +- vpfe->field = pixfmt->field; +- } else { +- ret = -EINVAL; +- } +- up(&vpfe->lock); +- break; +- } +- case VIDIOC_TRY_FMT: +- { +- struct v4l2_format *fmt = (struct v4l2_format *)arg; +- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +- ret = -EINVAL; +- } else { +- struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; +- if (pixfmt->width > vpfe->bounds.width +- || pixfmt->height > vpfe->bounds.height +- || (pixfmt->pixelformat != V4L2_PIX_FMT_UYVY +- && pixfmt->pixelformat != +- V4L2_PIX_FMT_YUYV)) { +- ret = -EINVAL; +- } +- } +- break; +- } +- case VIDIOC_G_STD: +- { +- v4l2_std_id *id = (v4l2_std_id *) arg; +- *id = vpfe->std; +- break; +- } +- case VIDIOC_S_STD: +- { +- v4l2_std_id id = *(v4l2_std_id *) arg; +- tvp5146_mode mode = TVP5146_MODE_INV; +- int sqp = 0; +- +- if (vpfe->started) { /* make sure streaming is not started */ +- ret = -EBUSY; +- break; +- } +- down_interruptible(&vpfe->lock); +- if (id & V4L2_STD_625_50) { +- vpfe->std = id; +- vpfe->bounds = vpfe->vwin = pal_bounds; +- vpfe->pixelaspect = pal_aspect; +- vpfe->ccdc_params.win = pal_bounds; +- +- } else if (id & V4L2_STD_525_60) { +- vpfe->std = id; +- vpfe->bounds = vpfe->vwin = ntsc_bounds; +- vpfe->pixelaspect = ntsc_aspect; +- vpfe->ccdc_params.win = ntsc_bounds; +- } else if (id & VPFE_STD_625_50_SQP) { +- vpfe->std = id; +- vpfe->bounds = vpfe->vwin = palsp_bounds; +- vpfe->pixelaspect = sp_aspect; +- sqp = 1; +- id >>= 32; +- } else if (id & VPFE_STD_525_60_SQP) { +- vpfe->std = id; +- sqp = 1; +- vpfe->std = id; +- id >>= 32; +- vpfe->bounds = vpfe->vwin = ntscsp_bounds; +- vpfe->pixelaspect = sp_aspect; +- vpfe->ccdc_params.win = ntscsp_bounds; +- } else if (id & VPFE_STD_AUTO) { +- mode = TVP5146_MODE_AUTO; +- vpfe->bounds = vpfe->vwin = pal_bounds; +- vpfe->pixelaspect = pal_aspect; +- vpfe->ccdc_params.win = pal_bounds; +- vpfe->std = id; +- } else if (id & VPFE_STD_AUTO_SQP) { +- vpfe->std = id; +- vpfe->bounds = vpfe->vwin = palsp_bounds; +- vpfe->pixelaspect = sp_aspect; +- sqp = 1; +- mode = TVP5146_MODE_AUTO_SQP; +- vpfe->pixelaspect = sp_aspect; +- } else { +- ret = -EINVAL; +- } +- if (id == V4L2_STD_PAL_60) { +- mode = TVP5146_MODE_PAL_60; +- } else if (id == V4L2_STD_PAL_M) { +- mode = TVP5146_MODE_PAL_M; +- } else if (id == V4L2_STD_PAL_Nc +- || id == V4L2_STD_PAL_N) { +- mode = TVP5146_MODE_PAL_CN; +- } else if (id & V4L2_STD_PAL) { +- mode = TVP5146_MODE_PAL; +- } else if (id & V4L2_STD_NTSC) { +- mode = TVP5146_MODE_NTSC; +- } else if (id & V4L2_STD_SECAM) { +- mode = TVP5146_MODE_SECAM; +- } +- vpfe->tvp5146_params.mode = mode | (sqp << 3); +- tvp5146_ctrl(TVP5146_CONFIG, &vpfe->tvp5146_params); +- +- up(&vpfe->lock); +- break; +- } +- case VIDIOC_ENUMSTD: +- { +- struct v4l2_standard *std = (struct v4l2_standard *)arg; +- u32 index = std->index; +- memset(std, 0, sizeof(*std)); +- std->index = index; +- if (index == 0) { +- std->id = V4L2_STD_525_60; +- strcpy(std->name, "SD-525line-30fps"); +- std->framelines = 525; +- std->frameperiod.numerator = 1001; +- std->frameperiod.denominator = 30000; +- } else if (index == 1) { +- std->id = V4L2_STD_625_50; +- strcpy(std->name, "SD-625line-25fps"); +- std->framelines = 625; +- std->frameperiod.numerator = 1; +- std->frameperiod.denominator = 25; +- } else if (index == 2) { +- std->id = VPFE_STD_625_50_SQP; +- strcpy(std->name, +- "SD-625line-25fps square pixel"); +- std->framelines = 625; +- std->frameperiod.numerator = 1; +- std->frameperiod.denominator = 25; +- } else if (index == 3) { +- std->id = VPFE_STD_525_60_SQP; +- strcpy(std->name, +- "SD-525line-25fps square pixel"); +- std->framelines = 525; +- std->frameperiod.numerator = 1001; +- std->frameperiod.denominator = 30000; +- } else if (index == 4) { +- std->id = VPFE_STD_AUTO; +- strcpy(std->name, "automatic detect"); +- std->framelines = 625; +- std->frameperiod.numerator = 1; +- std->frameperiod.denominator = 1; +- } else if (index == 5) { +- std->id = VPFE_STD_AUTO_SQP; +- strcpy(std->name, +- "automatic detect square pixel"); +- std->framelines = 625; +- std->frameperiod.numerator = 1; +- std->frameperiod.denominator = 1; +- } else { +- ret = -EINVAL; +- } +- break; +- } +- case VIDIOC_ENUMINPUT: +- { +- u32 index=0; +- struct v4l2_input *input = (struct v4l2_input *)arg; +- if (input->index > 1) /* only two inputs are available */ +- ret = -EINVAL; +- index = input->index; +- memset(input, 0, sizeof(*input)); +- input->index = index; +- input->type = V4L2_INPUT_TYPE_CAMERA; +- input->std = V4L2_STD_ALL; +- if(input->index == 0){ +- sprintf(input->name, "COMPOSITE"); +- }else if(input->index == 1) { +- sprintf(input->name, "S-VIDEO"); +- } +- break; +- } +- case VIDIOC_G_INPUT: +- { +- int *index = (int *)arg; +- *index = vpfe->tvp5146_params.amuxmode; +- break; +- } +- case VIDIOC_S_INPUT: +- { +- int *index = (int *)arg; +- if (*index > 1 || *index < 0) { +- ret = -EINVAL; +- } +- vpfe->tvp5146_params.amuxmode = *index; +- tvp5146_ctrl(TVP5146_SET_AMUXMODE, index); +- break; +- } +- case VIDIOC_CROPCAP: +- { +- struct v4l2_cropcap *cropcap = +- (struct v4l2_cropcap *)arg; +- cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +- down_interruptible(&vpfe->lock); +- cropcap->bounds = cropcap->defrect = vpfe->vwin; +- cropcap->pixelaspect = vpfe->pixelaspect; +- up(&vpfe->lock); +- break; +- } +- case VIDIOC_G_PARM: +- { +- struct v4l2_streamparm *parm = +- (struct v4l2_streamparm *)arg; +- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +- /* only capture is supported */ +- ret = -EINVAL; +- } else { +- struct v4l2_captureparm *capparm = +- &parm->parm.capture; +- memset(capparm, 0, +- sizeof(struct v4l2_captureparm)); +- down_interruptible(&vpfe->lock); +- if (vpfe->std & V4L2_STD_625_50) { +- capparm->timeperframe.numerator = 1; +- capparm->timeperframe.denominator = 25; /* PAL 25fps */ +- } else { +- capparm->timeperframe.numerator = 1001; +- capparm->timeperframe.denominator = 30000; /*NTSC 29.97fps */ +- } +- capparm->readbuffers = vpfe->numbuffers; +- up(&vpfe->lock); +- } +- break; +- } +- case VIDIOC_G_CTRL: +- down_interruptible(&vpfe->lock); +- tvp5146_ctrl(VIDIOC_G_CTRL, arg); +- up(&vpfe->lock); +- break; +- case VIDIOC_S_CTRL: +- down_interruptible(&vpfe->lock); +- tvp5146_ctrl(VIDIOC_S_CTRL, arg); +- up(&vpfe->lock); +- break; +- case VIDIOC_QUERYCTRL: +- down_interruptible(&vpfe->lock); +- tvp5146_ctrl(VIDIOC_QUERYCTRL, arg); +- up(&vpfe->lock); +- break; +- case VIDIOC_G_CROP: +- { +- struct v4l2_crop *crop = arg; +- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +- ret = -EINVAL; +- } else { +- crop->c = vpfe->vwin; +- } +- break; +- } +- case VIDIOC_S_CROP: +- { +- struct v4l2_crop *crop = arg; +- ccdc_params_ycbcr *params = &vpfe->ccdc_params; +- if (vpfe->started) { /* make sure streaming is not started */ +- ret = -EBUSY; +- break; +- } +- /*adjust the width to 16 pixel boundry */ +- crop->c.width = ((crop->c.width + 15 )/16 ) * 16; +- +- /* make sure parameters are valid */ +- if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE +- && (crop->c.left + crop->c.width +- <= vpfe->bounds.left + vpfe->bounds.width) +- && (crop->c.top + crop->c.height +- <= vpfe->bounds.top + vpfe->bounds.height)) { +- +- down_interruptible(&vpfe->lock); +- vpfe->vwin = crop->c; +- params->win = vpfe->vwin; +- up(&vpfe->lock); +- } else { +- ret = -EINVAL; +- } +- break; +- } +- case VIDIOC_QUERYSTD: +- { +- v4l2_std_id *id = (v4l2_std_id *) arg; +- down_interruptible(&vpfe->lock); +- ret = sense_std(id); +- up(&vpfe->lock); +- break; +- } +- case VIDIOC_G_PRIORITY: +- { +- enum v4l2_priority *p = arg; +- *p = v4l2_prio_max(&vpfe->prio); +- break; +- } +- case VIDIOC_S_PRIORITY: +- { +- enum v4l2_priority *p = arg; +- ret = v4l2_prio_change(&vpfe->prio, &fh->prio, *p); +- break; +- } +- +- case VIDIOC_REQBUFS: +- if (vpfe->io_usrs != 0) { +- ret = -EBUSY; +- break; +- } +- down_interruptible(&vpfe->lock); +- videobuf_queue_init(&vpfe->bufqueue, &video_qops, NULL, +- &vpfe->irqlock, V4L2_BUF_TYPE_VIDEO_CAPTURE, vpfe->field, +- sizeof(struct videobuf_buffer), fh); +- +- videobuf_set_buftype(&vpfe->bufqueue, VIDEOBUF_BUF_LINEAR); +- +- fh->io_allowed = TRUE; +- vpfe->io_usrs = 1; +- INIT_LIST_HEAD(&vpfe->dma_queue); +- ret = videobuf_reqbufs(&vpfe->bufqueue, arg); +- up(&vpfe->lock); +- break; +- case VIDIOC_QUERYBUF: +- ret = videobuf_querybuf(&vpfe->bufqueue, arg); +- break; +- case VIDIOC_QBUF: +- if (!fh->io_allowed) +- ret = -EACCES; +- else +- ret = videobuf_qbuf(&vpfe->bufqueue, arg); +- break; +- case VIDIOC_DQBUF: +- if (!fh->io_allowed) +- ret = -EACCES; +- else +- ret = videobuf_dqbuf(&vpfe->bufqueue, arg, 0); +- break; +- case VIDIOC_STREAMON: +- if (!fh->io_allowed) { +- ret = -EACCES; +- break; +- } +- if(vpfe->started){ +- ret = -EBUSY; +- break; +- } +- ret = videobuf_streamon(&vpfe->bufqueue); +- if(ret) break; +- +- down_interruptible(&vpfe->lock); +- /* get the current and next frame buffers */ +- /* we expect at least one buffer is in driver at this point */ +- /* if not, error is returned */ +- if (list_empty(&vpfe->dma_queue)) { +- ret = -EIO; +- break; +- } +- debug_print(KERN_INFO "cur frame %x.\n", +- vpfe->dma_queue.next); +- vpfe->nextFrm = vpfe->curFrm = +- list_entry(vpfe->dma_queue.next, +- struct videobuf_buffer, queue); +- /* remove the buffer from the queue */ +- list_del(&vpfe->curFrm->queue); +- vpfe->curFrm->state = STATE_ACTIVE; +- +- /* sense the current video input standard */ +- tvp5146_ctrl(TVP5146_CONFIG, &vpfe->tvp5146_params); +- /* configure the ccdc and resizer as needed */ +- /* start capture by enabling CCDC and resizer */ +- ccdc_config_ycbcr(&vpfe->ccdc_params); +- /* setup the memory address for the frame buffer */ +- ccdc_setfbaddr(((unsigned long)(vpfe->curFrm->boff))); +- /* enable CCDC */ +- vpfe->field_id = 0; +- vpfe->started = TRUE; +- vpfe->mode_changed = FALSE; +- vpfe->field_offset = +- (vpfe->vwin.height - 2) * vpfe->vwin.width; +- ccdc_enable(TRUE); +- up(&vpfe->lock); +- debug_print(KERN_INFO "started video streaming.\n"); +- break; +- case VIDIOC_STREAMOFF: +- { +- if (!fh->io_allowed) { +- ret = -EACCES; +- break; +- } +- if(!vpfe->started){ +- ret = -EINVAL; +- break; +- } +- /* disable CCDC */ +- down_interruptible(&vpfe->lock); +- ccdc_enable(FALSE); +- vpfe->started = FALSE; +- up(&vpfe->lock); +- ret = videobuf_streamoff(&vpfe->bufqueue); +- break; +- } +- case VPFE_CMD_CONFIG_CCDC: +- { +- /* this can be used directly and bypass the V4L2 APIs */ +- ccdc_params_ycbcr *params = &vpfe->ccdc_params; +- if(vpfe->started){ +- /* only allowed if streaming is not started */ +- ret = -EBUSY; +- break; +- } +- down_interruptible(&vpfe->lock); +- /* make sure the other v4l2 related fields +- have consistant settings */ +- *params = (*(ccdc_params_ycbcr *) arg); +- vpfe->vwin = params->win; +- if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { +- vpfe->field = V4L2_FIELD_INTERLACED; +- } else if (params->buf_type == +- CCDC_BUFTYPE_FLD_SEPARATED) { +- vpfe->field = V4L2_FIELD_SEQ_TB; +- } +- if (params->pix_order == CCDC_PIXORDER_YCBYCR) { +- vpfe->pixelfmt = V4L2_PIX_FMT_YUYV; +- } else if (params->pix_order == CCDC_PIXORDER_CBYCRY) { +- vpfe->pixelfmt = V4L2_PIX_FMT_UYVY; +- } +- up(&vpfe->lock); +- break; +- } +- case VPFE_CMD_CONFIG_TVP5146: +- /* this can be used directly and bypass the V4L2 APIs */ +- { +- /* the settings here must be consistant with that of the CCDC's, +- driver does not check the consistancy */ +- tvp5146_params *params = (tvp5146_params *) arg; +- v4l2_std_id std = 0; +- if(vpfe->started){ +- /* only allowed if streaming is not started */ +- ret = -EBUSY; +- break; +- } +- down_interruptible(&vpfe->lock); +- /*make sure the other v4l2 related fields have consistant settings */ +- switch (params->mode & 0x7) { +- case TVP5146_MODE_NTSC: +- std = V4L2_STD_NTSC; +- break; +- case TVP5146_MODE_PAL: +- std = V4L2_STD_PAL; +- break; +- case TVP5146_MODE_PAL_M: +- std = V4L2_STD_PAL_M; +- break; +- case TVP5146_MODE_PAL_CN: +- std = V4L2_STD_PAL_N; +- break; +- case TVP5146_MODE_SECAM: +- std = V4L2_STD_SECAM; +- break; +- case TVP5146_MODE_PAL_60: +- std = V4L2_STD_PAL_60; +- break; +- } +- +- if (params->mode & 0x8) { /* square pixel mode */ +- std <<= 32; +- } +- +- if (params->mode == TVP5146_MODE_AUTO) { /* auto-detection modes */ +- std = VPFE_STD_AUTO; +- } else if (params->mode == TVP5146_MODE_AUTO_SQP) { +- std = VPFE_STD_AUTO_SQP; +- } +- +- if (std & V4L2_STD_625_50) { +- vpfe->bounds = pal_bounds; +- vpfe->pixelaspect = pal_aspect; +- } else if (std & V4L2_STD_525_60) { +- vpfe->bounds = ntsc_bounds; +- vpfe->pixelaspect = ntsc_aspect; +- } else if (std & VPFE_STD_625_50_SQP) { +- vpfe->bounds = palsp_bounds; +- vpfe->pixelaspect = sp_aspect; +- } else if (std & VPFE_STD_525_60_SQP) { +- vpfe->bounds = ntscsp_bounds; +- vpfe->pixelaspect = sp_aspect; +- } +- vpfe->std = std; +- tvp5146_ctrl(TVP5146_CONFIG, params); +- vpfe->tvp5146_params = *params; +- up(&vpfe->lock); +- break; +- } +- default: +- ret = -ENOIOCTLCMD; +- break; +- } /* end switch(cmd) */ +- return ret; +-} +- +-static int vpfe_ioctl(struct inode *inode, struct file *file, +- unsigned int cmd, unsigned long arg) +-{ +- int ret; +- ret = video_usercopy(inode, file, cmd, arg, vpfe_doioctl); +- if( cmd == VIDIOC_S_FMT || cmd == VIDIOC_TRY_FMT ){ +- ret = video_usercopy(inode, file, VIDIOC_G_FMT, +- arg, vpfe_doioctl); +- } +- return ret; +-} +- +-static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) +-{ +- return videobuf_mmap_mapper(&vpfe_device.bufqueue, vma); +-} +- +-static int vpfe_open(struct inode *inode, struct file *filep) +-{ +- int minor = iminor(inode); +- vpfe_obj *vpfe = NULL; +- vpfe_fh *fh = NULL; +- +- debug_print(KERN_INFO "vpfe: open minor=%d\n", minor); +- +- /* check to make sure the minor numbers match */ +- if (vpfe_device.video_dev && vpfe_device.video_dev->minor == minor) { +- vpfe = &vpfe_device; +- } else { /* device not found here */ +- return -ENODEV; +- } +- +- /* allocate per filehandle data */ +- if ((fh = kmalloc(sizeof(*fh), GFP_KERNEL)) == NULL) { +- return -ENOMEM; +- } +- filep->private_data = fh; +- fh->dev = vpfe; +- fh->io_allowed = FALSE; +- fh->prio = V4L2_PRIORITY_UNSET; +- v4l2_prio_open(&vpfe->prio, &fh->prio); +- vpfe->usrs++; +- +- return 0; +-} +- +-static int vpfe_release(struct inode *inode, struct file *filep) +-{ +- vpfe_fh *fh = filep->private_data; +- vpfe_obj *vpfe = fh->dev; +- +- down_interruptible(&vpfe->lock); +- if (fh->io_allowed) { +- vpfe->io_usrs = 0; +- ccdc_enable(FALSE); +- vpfe->started = FALSE; +- videobuf_queue_cancel(&vpfe->bufqueue); +- vpfe->numbuffers = VPFE_DEFNUM_FBUFS; +- } +- vpfe->usrs--; +- v4l2_prio_close(&vpfe->prio, &fh->prio); +- filep->private_data = NULL; +- kfree(fh); +- up(&vpfe->lock); +- +- return 0; +-} +- +-static struct file_operations vpfe_fops = { +- .owner = THIS_MODULE, +- .open = vpfe_open, +- .release = vpfe_release, +- .ioctl = vpfe_ioctl, +- .mmap = vpfe_mmap +-}; +- +-static struct video_device vpfe_video_template = { +- .name = "vpfe", +- .type = VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES, +- .hardware = 0, +- .fops = &vpfe_fops, +- .minor = -1, +-}; +- +-static void vpfe_platform_release(struct device *device) +-{ +- /* This is called when the reference count goes to zero. */ +-} +- +-static int __init vpfe_probe(struct device *device) +-{ +- struct video_device *vfd; +- vpfe_obj *vpfe = &vpfe_device; +- +- /* alloc video device */ +- if ((vfd = video_device_alloc()) == NULL) { +- return -ENOMEM; +- } +- *vfd = vpfe_video_template; +- vfd->dev = device; +- vfd->release = video_device_release; +- snprintf(vfd->name, sizeof(vfd->name), "DM644X_VPFE_DRIVER_V%d.%d.%d", +- (VPFE_VERSION_CODE >> 16) & 0xff, +- (VPFE_VERSION_CODE >> 8) & 0xff, (VPFE_VERSION_CODE) & 0xff); +- +- vpfe->video_dev = vfd; +- vpfe->usrs = 0; +- vpfe->io_usrs = 0; +- vpfe->started = FALSE; +- vpfe->latest_only = TRUE; +- +- v4l2_prio_init(&vpfe->prio); +- init_MUTEX(&vpfe->lock); +- /* register video device */ +- debug_print(KERN_INFO "trying to register vpfe device.\n"); +- debug_print(KERN_INFO "vpfe=%x,vpfe->video_dev=%x\n", (int)vpfe, +- (int)&vpfe->video_dev); +- if (video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1) < 0) { +- video_device_release(vpfe->video_dev); +- vpfe->video_dev = NULL; +- return -1; +- } +- +- debug_print(KERN_INFO "DM644X vpfe: driver version V%d.%d.%d loaded\n", +- (VPFE_VERSION_CODE >> 16) & 0xff, +- (VPFE_VERSION_CODE >> 8) & 0xff, +- (VPFE_VERSION_CODE) & 0xff); +- +- debug_print(KERN_INFO "vpfe: registered device video%d\n", +- vpfe->video_dev->minor & 0x1f); +- +- /* all done */ +- return 0; +-} +- +-static int vpfe_remove(struct device *device) +-{ +- /* un-register device */ +- video_unregister_device(vpfe_device.video_dev); +- +- return 0; +-} +- +-#ifdef NEW +-static struct platform_driver vpfe_driver = { +- .driver = { +- .name = "VPFE", +- .owner = THIS_MODULE, +- }, +- .probe = vpfe_probe, +- .remove = vpfe_remove, +-}; +- +-#else +-static struct device_driver vpfe_driver = { +- .name = "vpfe", +- .bus = &platform_bus_type, +- .probe = vpfe_probe, +- .remove = vpfe_remove, +-}; +-#endif +- +-static struct platform_device _vpfe_device = { +- .name = "vpfe", +- .id = 1, +- .dev = { +- .release = vpfe_platform_release, +- } +-}; +- +-static int vpfe_init(void) +-{ +- int i = 0; +- void *mem; +- /* allocate memory at initialization time to guarentee availability */ +- for (i = 0; i < VPFE_DEFNUM_FBUFS; i++) { +- mem = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, +- VPFE_MAX_FBUF_ORDER); +- if (mem) { +- unsigned long adr = (unsigned long)mem; +- u32 size = PAGE_SIZE << VPFE_MAX_FBUF_ORDER; +- while (size > 0) { +- /* make sure the frame buffers +- are never swapped out of memory */ +- SetPageReserved(virt_to_page(adr)); +- adr += PAGE_SIZE; +- size -= PAGE_SIZE; +- } +- vpfe_device.fbuffers[i] = (u8 *) mem; +- debug_print(KERN_INFO "memory address %d\t%x\n", i, +- mem); +- } else { +- while (--i >= 0) { +- free_pages((unsigned long)vpfe_device.fbuffers[i], +- VPFE_MAX_FBUF_ORDER); +- } +- debug_print(KERN_INFO +- "frame buffer memory allocation failed.\n"); +- return -ENOMEM; +- } +- } +- if (driver_register(&vpfe_driver) != 0) { +- debug_print(KERN_INFO "driver registration failed\n"); +- return -1; +- } +- if (platform_device_register(&_vpfe_device) != 0) { +- driver_unregister(&vpfe_driver); +- debug_print(KERN_INFO "device registration failed\n"); +- return -1; +- } +- +- ccdc_reset(); +- tvp5146_ctrl(TVP5146_RESET, NULL); +- /* configure the tvp5146 to default parameters */ +- tvp5146_ctrl(TVP5146_CONFIG, &vpfe_device.tvp5146_params); +- /* setup interrupt handling */ +- request_irq(IRQ_VDINT0, vpfe_isr, SA_INTERRUPT, +- "dm644xv4l2", (void *)&vpfe_device); +- +- printk(KERN_INFO "DaVinci v4l2 capture driver V1.0 loaded\n"); +- return 0; +-} +- +-static void vpfe_cleanup(void) +-{ +- int i = vpfe_device.numbuffers; +- platform_device_unregister(&_vpfe_device); +- driver_unregister(&vpfe_driver); +- /* disable interrupt */ +- free_irq(IRQ_VDINT0, &vpfe_device); +- +- while (--i >= 0) { +- free_pages((unsigned long)vpfe_device.fbuffers[i], +- VPFE_MAX_FBUF_ORDER); +- } +- debug_print(KERN_INFO "vpfe: un-registered device video.\n"); +-} +- +-module_init(vpfe_init); +-module_exit(vpfe_cleanup); +diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h +new file mode 100644 +index 0000000..c2b4e11 +--- /dev/null ++++ b/include/media/davinci/vpfe_capture.h +@@ -0,0 +1,272 @@ ++/* ++ * Copyright (C) 2008-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _VPFE_CAPTURE_H ++#define _VPFE_CAPTURE_H ++ ++#ifdef __KERNEL__ ++ ++/* Header files */ ++#include <linux/videodev2.h> ++#include <media/v4l2-ioctl.h> ++#include <media/v4l2-int-device.h> ++#include <media/videobuf-dma-contig.h> ++#include <media/davinci/ccdc_hw_device.h> ++ ++#define VPFE_CAPTURE_NUM_DECODERS 5 ++ ++/* Macros */ ++#define VPFE_MAJOR_RELEASE 0 ++#define VPFE_MINOR_RELEASE 0 ++#define VPFE_BUILD 1 ++#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \ ++ (VPFE_MINOR_RELEASE << 8) | \ ++ VPFE_BUILD) ++ ++#define VPFE_VALID_FIELD(field) ((V4L2_FIELD_ANY == field) || \ ++ (V4L2_FIELD_NONE == field) || \ ++ (V4L2_FIELD_INTERLACED == field) || \ ++ (V4L2_FIELD_SEQ_TB == field)) ++ ++#define VPFE_VALID_BUFFER_TYPE(buftype) { \ ++ (V4L2_BUF_TYPE_VIDEO_CAPTURE == buftype) } ++ ++#define VPFE_CAPTURE_MAX_DEVICES 1 ++#define VPFE_MAX_DECODER_STD 50 ++#define VPFE_TIMER_COUNT 5 ++#define VPFE_SLICED_BUF_SIZE 256 ++#define VPFE_SLICED_MAX_SERVICES 3 ++#define VPFE_HBI_INDEX 2 ++#define VPFE_VBI_INDEX 1 ++#define VPFE_VIDEO_INDEX 0 ++ ++/* Define for device type to be passed in init */ ++#define MT9T001 0 ++#define TVP5146 1 ++#define MT9T031 2 ++#define MT9P031 3 ++#define TVP7002 4 ++ ++#define VPFE_NUMBER_OF_OBJECTS 1 ++ ++/* Macros */ ++#define ISALIGNED(a) (0 == (a % 32)) ++#define ISEXTERNALCMD(cmd) ((VPFE_CMD_S_DECODER_PARAMS == cmd) || \ ++ (VPFE_CMD_G_DECODER_PARAMS == cmd) || \ ++ (VPFE_CMD_S_CCDC_PARAMS == cmd) || \ ++ (VPFE_CMD_G_CCDC_PARAMS == cmd) || \ ++ (VPFE_CMD_CONFIG_CCDC_YCBCR == cmd) || \ ++ (VPFE_CMD_CONFIG_CCDC_RAW == cmd) || \ ++ (VPFE_CMD_CONFIG_TVP5146 == cmd) || \ ++ (VPFE_CMD_S_MT9T001_PARAMS == cmd) || \ ++ (VPFE_CMD_G_MT9T001_PARAMS == cmd)) ++ ++#include <media/v4l2-dev.h> ++#define VPFE_MAX_SECOND_RESOLUTION_SIZE (640 * 480 * 2) ++#define ROUND32(x) ((((x)+31) >> 5) << 5) ++#define ISNULL(val) ((val == NULL) ? 1 : 0) ++#define VPFE_MAX_PIX_FORMATS 6 ++enum vpfe_irq_use_type { ++ VPFE_USE_CCDC_IRQ, ++ VPFE_USE_IMP_IRQ, ++ VPFE_NO_IRQ ++}; ++ ++/* enumerated data types */ ++/* Enumerated data type to give id to each device per channel */ ++enum vpfe_channel_id { ++ /* Channel0 Video */ ++ VPFE_CHANNEL0_VIDEO = 0, ++ /* Channel1 Video */ ++ VPFE_CHANNEL1_VIDEO, ++}; ++ ++/* structures */ ++/* Table to keep track of the standards supported in all the decoders */ ++struct vpfe_decoder_std_tbl { ++ u8 dec_idx; ++ u8 std_idx; ++ v4l2_std_id std; ++}; ++ ++enum output_src { ++ VPFE_CCDC_OUT = 1, ++ VPFE_IMP_PREV_OUT = 2, ++ VPFE_IMP_RSZ_OUT = 4 ++}; ++ ++struct vpfe_pixel_format { ++ unsigned int pix_fmt; ++ char *desc; ++ enum vpfe_hw_pix_format hw_fmt; ++}; ++ ++struct vpfe_std_info { ++ int activepixels; ++ int activelines; ++ /* current frame format */ ++ int frame_format; ++}; ++ ++#define VPFE_MAX_DEC_INPUTS 5 ++ ++/* To map high level input name to decoder input */ ++struct vpfe_dec_input { ++ char dec_name[32]; ++ struct v4l2_input input; ++ struct v4l2_routing route; ++ int routing_supported; ++}; ++ ++struct vpfe_capture_input { ++ int num_inputs; ++ struct vpfe_dec_input inputs[VPFE_MAX_DEC_INPUTS]; ++ int current_input; ++}; ++ ++struct video_obj { ++ /* Keeps track of the information about the standard */ ++ struct vpfe_std_info std_info; ++ /* index into std table */ ++ int index; ++ /* All inputs to the driver */ ++ struct vpfe_capture_input *input; ++}; ++ ++struct common_obj { ++ /* Buffer specific parameters */ ++ /* List of buffer pointers for storing frames */ ++ u8 *fbuffers[VIDEO_MAX_FRAME]; ++ /* number of buffers in fbuffers */ ++ u32 numbuffers; ++ /* Pointer pointing to current v4l2_buffer */ ++ struct videobuf_buffer *curFrm; ++ /* Pointer pointing to next v4l2_buffer */ ++ struct videobuf_buffer *nextFrm; ++ /* This field keeps track of type of buffer exchange mechanism ++ * user has selected ++ */ ++ enum v4l2_memory memory; ++ /* Used to store pixel format */ ++ struct v4l2_format fmt; ++ /* Buffer queue used in video-buf */ ++ struct videobuf_queue buffer_queue; ++ /* Queue of filled frames */ ++ struct list_head dma_queue; ++ /* Used in video-buf */ ++ spinlock_t irqlock; ++ /* channel specifc parameters */ ++ /* lock used to access this structure */ ++ struct mutex lock; ++ /* number of users performing IO */ ++ u32 io_usrs; ++ /* Indicates whether streaming started */ ++ u8 started; ++ /* offset where second field starts from the starting of the ++ * buffer for field seperated YCbCr formats ++ */ ++ u32 field_off; ++ /* Indicates width of the image data */ ++ u32 width; ++ /* Indicates height of the image data */ ++ u32 height; ++ /* used when IMP is chained to store the crop window which ++ * is different from the image window ++ */ ++ struct v4l2_rect crop; ++}; ++ ++struct channel_obj { ++ /* V4l2 specific parameters */ ++ /* Identifies video device for this channel */ ++ struct video_device *video_dev; ++ /* Used to keep track of state of the priority */ ++ struct v4l2_prio_state prio; ++ /* number of open instances of the channel */ ++ u32 usrs; ++ /* Indicates id of the field which is being displayed */ ++ u32 field_id; ++ /* flag to indicate whether decoder is initialized */ ++ u8 initialized; ++ /* Identifies channel */ ++ enum vpfe_channel_id channel_id; ++ /* current interface parameters */ ++ struct v4l2_ifparm ifparams; ++ /* current interface type */ ++ enum vpfe_hw_if_type vpfe_if; ++ /* number of decoders registered with the master */ ++ u8 numdecoders; ++ /* decoder slave ptrs */ ++ struct v4l2_int_device *decoder[VPFE_CAPTURE_NUM_DECODERS]; ++ /* Index of the currently selected decoder */ ++ u8 current_decoder; ++ void *res1; ++ void *res2; ++ /* To track if we need to attach IPIPE IRQ or CCDC IRQ */ ++ enum vpfe_irq_use_type irq_type; ++ /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ ++ unsigned int ccdc_irq0; ++ unsigned int ccdc_irq1; ++ enum output_src out_from; ++ struct common_obj common[VPFE_NUMBER_OF_OBJECTS]; ++ struct video_obj video; ++}; ++ ++/* File handle structure */ ++struct vpfe_fh { ++ /* pointer to channel object for opened device */ ++ struct channel_obj *channel; ++ /* Indicates whether this file handle is doing IO */ ++ u8 io_allowed[VPFE_NUMBER_OF_OBJECTS]; ++ /* Used to keep track priority of this instance */ ++ enum v4l2_priority prio; ++ /* Used to indicate channel is initialize or not */ ++ u8 initialized; ++}; ++ ++/* vpfe device structure */ ++struct vpfe_device { ++ struct channel_obj *dev[CCDC_CAPTURE_NUM_CHANNELS]; ++}; ++ ++struct vpfe_config_params { ++ u8 min_numbuffers; ++ u8 numbuffers[CCDC_CAPTURE_NUM_CHANNELS]; ++ u32 min_bufsize[CCDC_CAPTURE_NUM_CHANNELS]; ++ u32 channel_bufsize[CCDC_CAPTURE_NUM_CHANNELS]; ++}; ++ ++ ++/* SoC Capture hardware interface */ ++extern struct ccdc_hw_device ccdc_hw_dev; ++#define CAPTURE_DRV_NAME "vpfe-capture" ++#endif /* End of __KERNEL__ */ ++ ++/* IOCTLs */ ++#define VPFE_CMD_LATEST_FRM_ONLY \ ++ _IOW('V', BASE_VIDIOC_PRIVATE + 1, int) ++#define VPFE_CMD_G_DECODER_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 2, \ ++ void *) ++#define VPFE_CMD_S_DECODER_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 3, \ ++ void *) ++#define VPFE_CMD_S_SOC_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 4, \ ++ void *) ++#define VPFE_CMD_G_SOC_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 5, \ ++ void *) ++ ++#endif /* _DAVINCI_VPFE_H */ +diff --git a/include/media/davinci/vpfe_types.h b/include/media/davinci/vpfe_types.h +new file mode 100644 +index 0000000..09d0531 +--- /dev/null ++++ b/include/media/davinci/vpfe_types.h +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (C) 2008-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option)any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef _VPFE_TYPES_H ++#define _VPFE_TYPES_H ++ ++#ifdef __KERNEL__ ++ ++enum vpfe_hw_if_type { ++ /* BT656 - 8 bit */ ++ VPFE_BT656, ++ /* BT1120 - 16 bit */ ++ VPFE_BT1120, ++ /* Raw Bayer */ ++ VPFE_RAW_BAYER, ++ /* YCbCr - 8 bit with external sync */ ++ VPFE_YCBCR_SYNC_8, ++ /* YCbCr - 16 bit with external sync */ ++ VPFE_YCBCR_SYNC_16, ++ /* BT656 - 10 bit */ ++ VPFE_BT656_10BIT ++}; ++ ++enum vpfe_sync_pol { ++ VPFE_SYNC_POSITIVE = 0, ++ VPFE_SYNC_NEGATIVE ++}; ++ ++/* Pixel format to be used across vpfe driver */ ++enum vpfe_hw_pix_format { ++ VPFE_BAYER_8BIT_PACK, ++ VPFE_BAYER_8BIT_PACK_ALAW, ++ VPFE_BAYER_8BIT_PACK_DPCM, ++ VPFE_BAYER_12BIT_PACK, ++ /* 16 bit Bayer */ ++ VPFE_BAYER, ++ VPFE_UYVY, ++ VPFE_YUYV, ++ VPFE_RGB565, ++ VPFE_RGB888, ++ /* YUV 420 */ ++ VPFE_YUV420, ++ /* YUV 420, Y data */ ++ VPFE_420_Y, ++ /* YUV 420, C data */ ++ VPFE_420_C, ++}; ++ ++/* interface description */ ++struct vpfe_hw_if_param { ++ enum vpfe_hw_if_type if_type; ++ enum vpfe_sync_pol hdpol; ++ enum vpfe_sync_pol vdpol; ++}; ++ ++#endif ++#endif +diff --git a/include/media/davinci_vpfe.h b/include/media/davinci_vpfe.h +deleted file mode 100644 +index 26e7b2c..0000000 +--- a/include/media/davinci_vpfe.h ++++ /dev/null +@@ -1,121 +0,0 @@ +-/* +- * Copyright (C) 2006 Texas Instruments Inc +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +-/* davinci_vpfe.h */ +- +-#ifndef DAVINCI_VPFE_H +-#define DAVINCI_VPFE_H +-#ifdef __KERNEL__ +-#include <media/v4l2-dev.h> +-#endif +- +-#include <media/ccdc_davinci.h> +-#include <media/tvp5146.h> +- +-#define TRUE 1 +-#define FALSE 0 +- +-/* vpfe specific video standards */ +-#define VPFE_STD_625_50_SQP ((V4L2_STD_625_50)<<32) +-#define VPFE_STD_525_60_SQP ((V4L2_STD_525_60)<<32) +-#define VPFE_STD_AUTO ((v4l2_std_id)(0x1000000000000000ULL)) +-#define VPFE_STD_AUTO_SQP ((v4l2_std_id)(0x2000000000000000ULL)) +- +-#define VPFE_CMD_CONFIG_CCDC _IOW('V',BASE_VIDIOC_PRIVATE + 1,ccdc_params_ycbcr) +-#define VPFE_CMD_LATEST_FRM_ONLY _IOW('V',BASE_VIDIOC_PRIVATE + 2,int) +-#define VPFE_CMD_CONFIG_TVP5146 _IOW('V',BASE_VIDIOC_PRIVATE + 3,tvp5146_params) +- +-/* settings for commonly used video formats */ +-#define VPFE_WIN_NTSC {0,0,720,480} +-#define VPFE_WIN_PAL {0,0,720,576} +-#define VPFE_WIN_NTSC_SP {0,0,640,480} /* ntsc square pixel */ +-#define VPFE_WIN_PAL_SP {0,0,768,576} /* pal square pixel */ +-#define VPFE_WIN_CIF {0,0,352,288} +-#define VPFE_WIN_QCIF {0,0,176,144} +-#define VPFE_WIN_QVGA {0,0,320,240} +-#define VPFE_WIN_SIF {0,0,352,240} +- +- +-#ifdef __KERNEL__ +- +-#include <media/video-buf.h> +- +-#define VPFE_MAJOR_RELEASE 0 +-#define VPFE_MINOR_RELEASE 0 +-#define VPFE_BUILD 1 +- +-#define VPFE_VERSION_CODE \ +- (VPFE_MAJOR_RELEASE<<16) | (VPFE_MINOR_RELEASE<<8) | VPFE_BUILD +- +-/* By default, the driver is setup for auto-swich mode */ +-#define VPFE_DEFAULT_STD VPFE_STD_AUTO +- +-#define VPFE_PIXELASPECT_NTSC {11, 10} +-#define VPFE_PIXELASPECT_PAL {54, 59} +-#define VPFE_PIXELASPECT_NTSC_SP {1, 1} +-#define VPFE_PIXELASPECT_PAL_SP {1, 1} +-#define VPFE_PIXELASPECT_DEFAULT {1, 1} +- +-#define VPFE_MAX_FRAME_WIDTH 768 /* account for PAL Square pixel mode */ +-#define VPFE_MAX_FRAME_HEIGHT 576 /* account for PAL */ +-/* 4:2:2 data */ +-#define VPFE_MAX_FBUF_SIZE (VPFE_MAX_FRAME_WIDTH*VPFE_MAX_FRAME_HEIGHT*2) +-/* frame buffers allocate at driver initialization time */ +-#define VPFE_DEFNUM_FBUFS 3 +- +-#define VPFE_MAX_FBUF_ORDER \ +- get_order(roundup_pow_of_two(VPFE_MAX_FBUF_SIZE)) +- +-/* device object */ +-typedef struct vpfe_obj { +- struct video_device *video_dev; +- struct videobuf_queue bufqueue;/* queue with frame buffers */ +- struct list_head dma_queue; +- u32 latest_only; /* indicate whether to return the most */ +- /* recent captured buffers only */ +- u32 usrs; +- u32 io_usrs; +- struct v4l2_prio_state prio; +- v4l2_std_id std; +- struct v4l2_rect vwin; +- struct v4l2_rect bounds; +- struct v4l2_fract pixelaspect; +- spinlock_t irqlock; +- struct semaphore lock; +- enum v4l2_field field; +- u32 pixelfmt; +- u32 numbuffers; +- u8* fbuffers[VIDEO_MAX_FRAME]; +- struct videobuf_buffer *curFrm; +- struct videobuf_buffer *nextFrm; +- int field_id; +- int mode_changed; +- int started; +- int field_offset; +- tvp5146_params tvp5146_params; +- ccdc_params_ycbcr ccdc_params; +-} vpfe_obj; +- +-/* file handle */ +-typedef struct vpfe_fh { +- struct vpfe_obj *dev; +- int io_allowed; +- enum v4l2_priority prio; +-} vpfe_fh; +-#endif +- +-#endif /* DAVINCI_VPFE_H */ +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci/vfpe2.patch b/recipes/linux/linux-davinci/vfpe2.patch new file mode 100644 index 0000000000..8915ee33b6 --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe2.patch @@ -0,0 +1,200 @@ +Subject: +[PATCH 2/7] interface for configuring CCDC and common ccdc types +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:22:39 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Adding an interface for configuring ccdc as per data format of decoder +output. Also adds a header file for common ccdc data types. + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + include/media/davinci/ccdc_common.h | 48 +++++++++++++ + include/media/davinci/ccdc_hw_device.h | 117 ++++++++++++++++++++++++++++++++ + 2 files changed, 165 insertions(+), 0 deletions(-) + create mode 100644 include/media/davinci/ccdc_common.h + create mode 100644 include/media/davinci/ccdc_hw_device.h + +diff --git a/include/media/davinci/ccdc_common.h b/include/media/davinci/ccdc_common.h +new file mode 100644 +index 0000000..0992af5 +--- /dev/null ++++ b/include/media/davinci/ccdc_common.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2008-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ **************************************************************************/ ++#ifndef _CCDC_COMMON_H ++#define _CCDC_COMMON_H ++enum ccdc_pixfmt { ++ CCDC_PIXFMT_RAW = 0, ++ CCDC_PIXFMT_YCBCR_16BIT = 1, ++ CCDC_PIXFMT_YCBCR_8BIT = 2 ++}; ++ ++enum ccdc_frmfmt { ++ CCDC_FRMFMT_PROGRESSIVE = 0, ++ CCDC_FRMFMT_INTERLACED = 1 ++}; ++ ++/* PIXEL ORDER IN MEMORY from LSB to MSB */ ++/* only applicable for 8-bit input mode */ ++enum ccdc_pixorder { ++ CCDC_PIXORDER_CBYCRY = 1, ++ CCDC_PIXORDER_YCBYCR = 0 ++}; ++ ++enum ccdc_buftype { ++ CCDC_BUFTYPE_FLD_INTERLEAVED, ++ CCDC_BUFTYPE_FLD_SEPARATED ++}; ++ ++enum ccdc_pinpol { ++ CCDC_PINPOL_POSITIVE = 0, ++ CCDC_PINPOL_NEGATIVE = 1 ++}; ++#endif +diff --git a/include/media/davinci/ccdc_hw_device.h b/include/media/davinci/ccdc_hw_device.h +new file mode 100644 +index 0000000..4ae9876 +--- /dev/null ++++ b/include/media/davinci/ccdc_hw_device.h +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (C) 2008 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ccdc device API ++ */ ++#ifndef _CCDC_HW_DEVICE_H ++#define _CCDC_HW_DEVICE_H ++ ++#ifdef __KERNEL__ ++#include <linux/videodev2.h> ++#include <linux/device.h> ++#include <media/davinci/vpfe_types.h> ++#include <media/davinci/ccdc_common.h> ++/* ++ * Maximum number of capture channels supported by VPFE ++ */ ++#define CCDC_CAPTURE_NUM_CHANNELS 1 ++/* ++ * vpfe hw interface ++ */ ++struct ccdc_hw_device { ++ ++ /* vpfe device name */ ++ char name[30]; ++ ++ /* Pointer to initialize function to initialize ccdc device */ ++ int (*open) (struct device *dev); ++ /* Set of functions pointers for control related functions. ++ * Use queryctrl of decoder interface to check if it is a decoder ++ * control id. If not passed to ccdc to process it ++ */ ++ /* set ccdc base address */ ++ void (*set_ccdc_base)(void *base, int size); ++ ++ /* set vpss base address */ ++ void (*set_vpss_base)(void *base, int size); ++ ++ /* get ccdc base */ ++ void * (*get_ccdc_base)(void); ++ ++ /* get vpss base */ ++ void * (*get_vpss_base)(void); ++ ++ void (*enable) (int en); ++ /* ++ * Pointer to function to enable or disable ccdc ++ */ ++ u32 (*reset) (void); ++ /* reset sbl. only for 6446 */ ++ void (*enable_out_to_sdram) (int en); ++ /* Pointer to function to set hw frame type */ ++ int (*set_hw_if_type) (enum vpfe_hw_if_type iface); ++ /* get interface parameters */ ++ int (*get_hw_if_params) (struct vpfe_hw_if_param *param); ++ /* Pointer to function to set parameters. Used ++ * for implementing VPFE_S_CCDC_PARAMS ++ */ ++ int (*setparams) (void *params); ++ /* Pointer to function to get parameter. Used ++ * for implementing VPFE_G_CCDC_PARAMS ++ */ ++ int (*getparams) (void *params); ++ /* Pointer to function to configure ccdc */ ++ int (*configure) (void); ++ ++ /* enumerate hw pix formats */ ++ int (*enum_pix)(enum vpfe_hw_pix_format *hw_pix, int i); ++ /* Pointer to function to set buffer type */ ++ int (*set_buftype) (enum ccdc_buftype buf_type); ++ /* Pointer to function to get buffer type */ ++ int (*get_buftype) (enum ccdc_buftype *buf_type); ++ /* Pointer to function to set frame format */ ++ int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); ++ /* Pointer to function to get frame format */ ++ int (*get_frame_format) (enum ccdc_frmfmt *frm_fmt); ++ /* Pointer to function to set buffer type */ ++ int (*get_pixelformat) (enum vpfe_hw_pix_format *pixfmt); ++ /* Pointer to function to get pixel format. Uses V4L2 type */ ++ int (*set_pixelformat) (enum vpfe_hw_pix_format pixfmt); ++ /* Pointer to function to set image window */ ++ int (*set_image_window) (struct v4l2_rect *win); ++ /* Pointer to function to set image window */ ++ int (*get_image_window) (struct v4l2_rect *win); ++ /* Pointer to function to get line length */ ++ int (*get_line_length) (unsigned int *len); ++ ++ /* Query SoC control IDs */ ++ int (*queryctrl)(struct v4l2_queryctrl *qctrl); ++ /* Set SoC control */ ++ int (*setcontrol)(struct v4l2_control *ctrl); ++ /* Get SoC control */ ++ int (*getcontrol)(struct v4l2_control *ctrl); ++ /* Pointer to function to set current standard info */ ++ /* Pointer to function to set frame buffer address */ ++ void (*setfbaddr) (unsigned long addr); ++ /* Pointer to function to get field id */ ++ int (*getfid) (void); ++ /* Pointer to deinitialize function */ ++ int (*close) (struct device *dev); ++}; ++ ++#endif ++#endif +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci/vfpe3.patch b/recipes/linux/linux-davinci/vfpe3.patch new file mode 100644 index 0000000000..f655b507a0 --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe3.patch @@ -0,0 +1,2558 @@ +Subject: +[PATCH 3/7] ccdc hw module and header file for DM355 +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:22:56 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Adds ccdc hw module and it's header file + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + drivers/media/video/davinci/ccdc_dm355.c | 1766 ++++++++++++++++++++++++++++++ + drivers/media/video/davinci/ccdc_dm355.h | 758 +++++++++++++ + 2 files changed, 2524 insertions(+), 0 deletions(-) + create mode 100644 drivers/media/video/davinci/ccdc_dm355.c + create mode 100644 drivers/media/video/davinci/ccdc_dm355.h + +diff --git a/drivers/media/video/davinci/ccdc_dm355.c b/drivers/media/video/davinci/ccdc_dm355.c +new file mode 100644 +index 0000000..b03dbaf +--- /dev/null ++++ b/drivers/media/video/davinci/ccdc_dm355.c +@@ -0,0 +1,1766 @@ ++/* ++ * Copyright (C) 2005-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <asm/page.h> ++#include <media/davinci/ccdc_hw_device.h> ++#include "ccdc_dm355.h" ++ ++static struct device *dev; ++ ++/*Object for CCDC raw mode */ ++static struct ccdc_params_raw ccdc_hw_params_raw = { ++ .pix_fmt = CCDC_PIXFMT_RAW, ++ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, ++ .win = CCDC_WIN_VGA, ++ .fid_pol = CCDC_PINPOL_POSITIVE, ++ .vd_pol = CCDC_PINPOL_POSITIVE, ++ .hd_pol = CCDC_PINPOL_POSITIVE, ++ .image_invert_enable = 0, ++ .data_sz = _10BITS, ++ .med_filt_thres = 0, ++ .mfilt1 = NO_MEDIAN_FILTER1, ++ .mfilt2 = NO_MEDIAN_FILTER2, ++ .ccdc_offset = 0, ++ .gain = { ++ .r_ye = 256, ++ .gb_g = 256, ++ .gr_cy = 256, ++ .b_mg = 256 ++ }, ++ .lpf_enable = 0, ++ .datasft = 2, ++ .alaw = { ++ .b_alaw_enable = 0, ++ .gama_wd = 2 ++ }, ++ .blk_clamp = { ++ .b_clamp_enable = 0, ++ .sample_pixel = 1, ++ .start_pixel = 0, ++ .dc_sub = 25 ++ }, ++ .blk_comp = { ++ .b_comp = 0, ++ .gb_comp = 0, ++ .gr_comp = 0, ++ .r_comp = 0 ++ }, ++ .vertical_dft = { ++ .ver_dft_en = 0 ++ }, ++ .lens_sh_corr = { ++ .lsc_enable = 0 ++ }, ++ .data_formatter_r = { ++ .fmt_enable = 0 ++ }, ++ .color_space_con = { ++ .csc_enable = 0 ++ }, ++ .col_pat_field0 = { ++ .olop = CCDC_GREEN_BLUE, ++ .olep = CCDC_BLUE, ++ .elop = CCDC_RED, ++ .elep = CCDC_GREEN_RED ++ }, ++ .col_pat_field1 = { ++ .olop = CCDC_GREEN_BLUE, ++ .olep = CCDC_BLUE, ++ .elop = CCDC_RED, ++ .elep = CCDC_GREEN_RED ++ } ++}; ++ ++ ++/*Object for CCDC ycbcr mode */ ++static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { ++ .win = CCDC_WIN_PAL, ++ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, ++ .frm_fmt = CCDC_FRMFMT_INTERLACED, ++ .fid_pol = CCDC_PINPOL_POSITIVE, ++ .vd_pol = CCDC_PINPOL_POSITIVE, ++ .hd_pol = CCDC_PINPOL_POSITIVE, ++ .bt656_enable = 1, ++ .pix_order = CCDC_PIXORDER_CBYCRY, ++ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED ++}; ++ ++static struct v4l2_queryctrl ccdc_control_info[CCDC_MAX_CONTROLS] = { ++ { ++ .id = CCDC_CID_R_GAIN, ++ .name = "R/Ye WB Gain", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .minimum = 0, ++ .maximum = 2047, ++ .step = 1, ++ .default_value = 256 ++ }, ++ { ++ .id = CCDC_CID_GR_GAIN, ++ .name = "Gr/Cy WB Gain", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .minimum = 0, ++ .maximum = 2047, ++ .step = 1, ++ .default_value = 256 ++ }, ++ { ++ .id = CCDC_CID_GB_GAIN, ++ .name = "Gb/G WB Gain", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .minimum = 0, ++ .maximum = 2047, ++ .step = 1, ++ .default_value = 256 ++ }, ++ { ++ .id = CCDC_CID_B_GAIN, ++ .name = "B/Mg WB Gain", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .minimum = 0, ++ .maximum = 2047, ++ .step = 1, ++ .default_value = 256 ++ }, ++ { ++ .id = CCDC_CID_OFFSET, ++ .name = "Offset", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .minimum = 0, ++ .maximum = 1023, ++ .step = 1, ++ .default_value = 0 ++ } ++}; ++ ++static struct ccdc_config_params_raw ccdc_hw_params_raw_temp; ++static enum vpfe_hw_if_type ccdc_if_type; ++static void *__iomem ccdc_base_addr; ++static int ccdc_addr_size; ++static void *__iomem vpss_base_addr; ++static int vpss_addr_size; ++ ++#define CCDC_MAX_RAW_BAYER_FORMATS 2 ++#define CCDC_MAX_RAW_YUV_FORMATS 2 ++ ++/* Raw Bayer formats */ ++enum vpfe_hw_pix_format ccdc_raw_bayer_hw_formats[CCDC_MAX_RAW_BAYER_FORMATS] = ++ {VPFE_BAYER_8BIT_PACK_ALAW, VPFE_BAYER}; ++ ++/* Raw YUV formats */ ++enum vpfe_hw_pix_format ccdc_raw_yuv_hw_formats[CCDC_MAX_RAW_YUV_FORMATS] = ++ {VPFE_UYVY, VPFE_YUYV}; ++ ++/* register access routines */ ++static inline u32 regr(u32 offset) ++{ ++ if (offset <= ccdc_addr_size) ++ return __raw_readl(ccdc_base_addr + offset); ++ else { ++ dev_err(dev, "offset exceeds ccdc register address space\n"); ++ return -1; ++ } ++} ++ ++static inline u32 regw(u32 val, u32 offset) ++{ ++ if (offset <= ccdc_addr_size) { ++ __raw_writel(val, ccdc_base_addr + offset); ++ return val; ++ } else { ++ dev_err(dev, "offset exceeds ccdc register address space\n"); ++ return -1; ++ } ++} ++ ++/* register access routines */ ++static inline u32 regr_bl(u32 offset) ++{ ++ if (offset <= vpss_addr_size) ++ return __raw_readl(vpss_base_addr + offset); ++ else { ++ dev_err(dev, "offset exceeds vpss register address space\n"); ++ return -1; ++ } ++} ++ ++static inline u32 regw_bl(u32 val, u32 offset) ++{ ++ if (offset <= vpss_addr_size) { ++ __raw_writel(val, vpss_base_addr + offset); ++ return val; ++ } else { ++ dev_err(dev, "offset exceeds vpss register address space\n"); ++ return -1; ++ } ++} ++static void ccdc_set_ccdc_base(void *addr, int size) ++{ ++ ccdc_base_addr = addr; ++ ccdc_addr_size = size; ++} ++ ++static void ccdc_set_vpss_base(void *addr, int size) ++{ ++ vpss_base_addr = addr; ++ vpss_addr_size = size; ++} ++ ++static void *ccdc_get_ccdc_base(void) ++{ ++ return (void *)ccdc_base_addr; ++} ++ ++static void *ccdc_get_vpss_base(void) ++{ ++ return (void *)vpss_base_addr; ++} ++ ++static void ccdc_enable(int en) ++{ ++ unsigned int temp; ++ temp = regr(SYNCEN); ++ temp &= (~0x1); ++ temp |= (en & 0x01); ++ regw(temp, SYNCEN); ++} ++ ++static void ccdc_enable_output_to_sdram(int en) ++{ ++ unsigned int temp; ++ temp = regr(SYNCEN); ++ temp &= (~(0x1 << 1)); ++ temp |= (en & 0x01) << 1; ++ regw(temp, SYNCEN); ++} ++ ++static void ccdc_config_gain_offset(void) ++{ ++ /* configure gain */ ++ regw(ccdc_hw_params_raw.gain.r_ye, RYEGAIN); ++ regw(ccdc_hw_params_raw.gain.gr_cy, GRCYGAIN); ++ regw(ccdc_hw_params_raw.gain.gb_g, GBGGAIN); ++ regw(ccdc_hw_params_raw.gain.b_mg, BMGGAIN); ++ /* configure offset */ ++ regw(ccdc_hw_params_raw.ccdc_offset, OFFSET); ++} ++ ++/* Query control. Only applicable for Bayer capture */ ++static int ccdc_queryctrl(struct v4l2_queryctrl *qctrl) ++{ ++ int i, id; ++ struct v4l2_queryctrl *control = NULL; ++ ++ dev_dbg(dev, "ccdc_queryctrl: start\n"); ++ if (NULL == qctrl) { ++ dev_err(dev, "ccdc_queryctrl : invalid user ptr\n"); ++ return -EINVAL; ++ } ++ ++ if (VPFE_RAW_BAYER != ccdc_if_type) { ++ dev_err(dev, ++ "ccdc_queryctrl : Not doing Raw Bayer Capture\n"); ++ return -EINVAL; ++ } ++ ++ id = qctrl->id; ++ memset(qctrl, 0, sizeof(struct v4l2_queryctrl)); ++ for (i = 0; i < CCDC_MAX_CONTROLS; i++) { ++ control = &ccdc_control_info[i]; ++ if (control->id == id) ++ break; ++ } ++ if (i == CCDC_MAX_CONTROLS) { ++ dev_err(dev, "ccdc_queryctrl : Invalid control ID\n"); ++ return -EINVAL; ++ } ++ memcpy(qctrl, control, sizeof(struct v4l2_queryctrl)); ++ dev_dbg(dev, "ccdc_queryctrl: end\n"); ++ return 0; ++} ++ ++static int ccdc_setcontrol(struct v4l2_control *ctrl) ++{ ++ int i; ++ struct v4l2_queryctrl *control = NULL; ++ struct ccdc_gain *gain = ++ &ccdc_hw_params_raw.gain; ++ ++ if (NULL == ctrl) { ++ dev_err(dev, "ccdc_setcontrol: invalid user ptr\n"); ++ return -EINVAL; ++ } ++ ++ if (ccdc_if_type != VPFE_RAW_BAYER) { ++ dev_err(dev, ++ "ccdc_setcontrol: Not doing Raw Bayer Capture\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < CCDC_MAX_CONTROLS; i++) { ++ control = &ccdc_control_info[i]; ++ if (control->id == ctrl->id) ++ break; ++ } ++ ++ if (i == CCDC_MAX_CONTROLS) { ++ dev_err(dev, "ccdc_queryctrl : Invalid control ID, 0x%x\n", ++ control->id); ++ return -EINVAL; ++ } ++ ++ if (ctrl->value > control->maximum) { ++ dev_err(dev, "ccdc_queryctrl : Invalid control value\n"); ++ return -EINVAL; ++ } ++ ++ switch (ctrl->id) { ++ case CCDC_CID_R_GAIN: ++ gain->r_ye = ctrl->value & CCDC_GAIN_MASK; ++ break; ++ case CCDC_CID_GR_GAIN: ++ gain->gr_cy = ctrl->value & CCDC_GAIN_MASK; ++ break; ++ case CCDC_CID_GB_GAIN: ++ gain->gb_g = ctrl->value & CCDC_GAIN_MASK; ++ break; ++ ++ case CCDC_CID_B_GAIN: ++ gain->b_mg = ctrl->value & CCDC_GAIN_MASK; ++ break; ++ default: ++ ccdc_hw_params_raw.ccdc_offset = ctrl->value & CCDC_OFFSET_MASK; ++ } ++ ++ /* set it in hardware */ ++ ccdc_config_gain_offset(); ++ return 0; ++} ++ ++static int ccdc_getcontrol(struct v4l2_control *ctrl) ++{ ++ int i; ++ struct v4l2_queryctrl *control = NULL; ++ ++ if (NULL == ctrl) { ++ dev_err(dev, "ccdc_setcontrol: invalid user ptr\n"); ++ return -EINVAL; ++ } ++ ++ if (ccdc_if_type != VPFE_RAW_BAYER) { ++ dev_err(dev, ++ "ccdc_setcontrol: Not doing Raw Bayer Capture\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < CCDC_MAX_CONTROLS; i++) { ++ control = &ccdc_control_info[i]; ++ if (control->id == ctrl->id) ++ break; ++ } ++ ++ if (i == CCDC_MAX_CONTROLS) { ++ dev_err(dev, "ccdc_queryctrl : Invalid control ID\n"); ++ return -EINVAL; ++ } ++ ++ switch (ctrl->id) { ++ case CCDC_CID_R_GAIN: ++ ctrl->value = ccdc_hw_params_raw.gain.r_ye; ++ break; ++ case CCDC_CID_GR_GAIN: ++ ctrl->value = ccdc_hw_params_raw.gain.gr_cy; ++ break; ++ case CCDC_CID_GB_GAIN: ++ ctrl->value = ccdc_hw_params_raw.gain.gb_g; ++ break; ++ case CCDC_CID_B_GAIN: ++ ctrl->value = ccdc_hw_params_raw.gain.b_mg; ++ break; ++ default: ++ /* offset */ ++ ctrl->value = ccdc_hw_params_raw.ccdc_offset; ++ } ++ /* set it in hardware */ ++ return 0; ++} ++ ++static void ccdc_reset(void) ++{ ++ int i, clkctrl; ++ /* disable CCDC */ ++ dev_dbg(dev, "\nstarting ccdc_reset..."); ++ ccdc_enable(0); ++ /* set all registers to default value */ ++ for (i = 0; i <= 0x15c; i += 4) ++ regw(0, i); ++ /* no culling support */ ++ regw(0xffff, CULH); ++ regw(0xff, CULV); ++ /* Set default Gain and Offset */ ++ ccdc_hw_params_raw.gain.r_ye = 256; ++ ccdc_hw_params_raw.gain.gb_g = 256; ++ ccdc_hw_params_raw.gain.gr_cy = 256; ++ ccdc_hw_params_raw.gain.b_mg = 256; ++ ccdc_hw_params_raw.ccdc_offset = 0; ++ ccdc_config_gain_offset(); ++ /* up to 12 bit sensor */ ++ regw(0x0FFF, OUTCLIP); ++ /* CCDC input Mux select directly from sensor */ ++ regw_bl(0x00, CCDCMUX); ++ dev_dbg(dev, "\nEnd of ccdc_reset..."); ++} ++ ++static int ccdc_open(struct device *device) ++{ ++ dev = device; ++ ccdc_reset(); ++ return 0; ++} ++ ++/* ++ * ======== ccdc_setwin ======== ++ * ++ * This function will configure the window size to ++ * be capture in CCDC reg ++ */ ++static void ccdc_setwin(struct ccdc_imgwin *image_win, ++ enum ccdc_frmfmt frm_fmt, int ppc) ++{ ++ int horz_start, horz_nr_pixels; ++ int vert_start, vert_nr_lines; ++ int mid_img = 0; ++ dev_dbg(dev, "\nStarting ccdc_setwin..."); ++ /* configure horizonal and vertical starts and sizes */ ++ horz_start = image_win->left << (ppc - 1); ++ horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; ++ ++ /*Writing the horizontal info into the registers */ ++ regw(horz_start & START_PX_HOR_MASK, SPH); ++ regw(horz_nr_pixels & NUM_PX_HOR_MASK, NPH); ++ vert_start = image_win->top; ++ ++ if (frm_fmt == CCDC_FRMFMT_INTERLACED) { ++ vert_nr_lines = (image_win->height >> 1) - 1; ++ vert_start >>= 1; ++ vert_start += 1; /* Since first line doesn't have any data */ ++ /* configure VDINT0 and VDINT1 */ ++ regw(vert_start, VDINT0); ++ } else { ++ vert_start += 1; /* Since first line doesn't have any data */ ++ vert_nr_lines = image_win->height - 1; ++ /* configure VDINT0 and VDINT1 */ ++ mid_img = vert_start + (image_win->height / 2); ++ regw(vert_start, VDINT0); ++ regw(mid_img, VDINT1); ++ } ++ regw(vert_start & START_VER_ONE_MASK, SLV0); ++ regw(vert_start & START_VER_TWO_MASK, SLV1); ++ regw(vert_nr_lines & NUM_LINES_VER, NLV); ++ dev_dbg(dev, "\nEnd of ccdc_setwin..."); ++} ++ ++static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) ++{ ++ if (ccdcparam->pix_fmt != 0) { ++ dev_err(dev, ++ "Invalid value of pix_fmt, only raw supported\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->frm_fmt != 0) { ++ dev_err(dev, ++ "Only Progressive frame format is supported\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->fid_pol != CCDC_PINPOL_POSITIVE ++ && ccdcparam->fid_pol != CCDC_PINPOL_NEGATIVE) { ++ dev_err(dev, "Invalid value of field id polarity\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->vd_pol != CCDC_PINPOL_POSITIVE ++ && ccdcparam->vd_pol != CCDC_PINPOL_NEGATIVE) { ++ dev_err(dev, "Invalid value of VD polarity\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->hd_pol != CCDC_PINPOL_POSITIVE ++ && ccdcparam->hd_pol != CCDC_PINPOL_NEGATIVE) { ++ dev_err(dev, "Invalid value of HD polarity\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->datasft < NO_SHIFT || ccdcparam->datasft > _6BIT) { ++ dev_err(dev, "Invalid value of data shift\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->mfilt1 < NO_MEDIAN_FILTER1 ++ || ccdcparam->mfilt1 > MEDIAN_FILTER1) { ++ dev_err(dev, "Invalid value of median filter1\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->mfilt2 < NO_MEDIAN_FILTER2 ++ || ccdcparam->mfilt2 > MEDIAN_FILTER2) { ++ dev_err(dev, "Invalid value of median filter2\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->ccdc_offset < 0 || ccdcparam->ccdc_offset > 1023) { ++ dev_err(dev, "Invalid value of offset\n"); ++ return -1; ++ } ++ ++ if ((ccdcparam->med_filt_thres < 0) ++ || (ccdcparam->med_filt_thres > 0x3FFF)) { ++ dev_err(dev, "Invalid value of median filter thresold\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->data_sz < _16BITS || ccdcparam->data_sz > _8BITS) { ++ dev_err(dev, "Invalid value of data size\n"); ++ return -1; ++ } ++ ++ if (ccdcparam->alaw.b_alaw_enable) { ++ if (ccdcparam->alaw.gama_wd < BITS_13_4 ++ || ccdcparam->alaw.gama_wd > BITS_09_0) { ++ dev_err(dev, "Invalid value of ALAW\n"); ++ return -1; ++ } ++ } ++ ++ if (ccdcparam->blk_clamp.b_clamp_enable) { ++ if (ccdcparam->blk_clamp.sample_pixel < _1PIXELS ++ || ccdcparam->blk_clamp.sample_pixel > _16PIXELS) { ++ dev_err(dev, "Invalid value of sample pixel\n"); ++ return -1; ++ } ++ if (ccdcparam->blk_clamp.sample_ln < _1LINES ++ || ccdcparam->blk_clamp.sample_ln > _16LINES) { ++ dev_err(dev, "Invalid value of sample lines\n"); ++ return -1; ++ } ++ ++ } ++ ++ if (ccdcparam->lens_sh_corr.lsc_enable) { ++ dev_err(dev, "Lens shadding correction is not supported\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ccdc_update_raw_params(void *arg) ++{ ++ struct ccdc_config_params_raw *raw = ++ (struct ccdc_config_params_raw *)arg; ++ ++ ccdc_hw_params_raw.pix_fmt = ++ raw->pix_fmt; ++ ccdc_hw_params_raw.frm_fmt = ++ raw->frm_fmt; ++ ccdc_hw_params_raw.win = ++ raw->win; ++ ccdc_hw_params_raw.fid_pol = ++ raw->fid_pol; ++ ccdc_hw_params_raw.vd_pol = ++ raw->vd_pol; ++ ccdc_hw_params_raw.hd_pol = ++ raw->hd_pol; ++ ccdc_hw_params_raw.buf_type = ++ raw->buf_type; ++ ccdc_hw_params_raw.datasft = ++ raw->datasft; ++ ccdc_hw_params_raw.mfilt1 = ++ raw->mfilt1; ++ ccdc_hw_params_raw.mfilt2 = ++ raw->mfilt2; ++ ccdc_hw_params_raw.lpf_enable = ++ raw->lpf_enable; ++ ccdc_hw_params_raw.horz_flip_enable = ++ raw->horz_flip_enable; ++ ccdc_hw_params_raw.ccdc_offset = ++ raw->ccdc_offset; ++ ccdc_hw_params_raw.med_filt_thres = ++ raw->med_filt_thres; ++ ccdc_hw_params_raw.image_invert_enable = ++ raw->image_invert_enable; ++ ccdc_hw_params_raw.data_sz = ++ raw->data_sz; ++ ccdc_hw_params_raw.alaw = ++ raw->alaw; ++ ccdc_hw_params_raw.data_offset_s = ++ raw->data_offset_s; ++ ccdc_hw_params_raw.blk_clamp = ++ raw->blk_clamp; ++ ccdc_hw_params_raw.vertical_dft = ++ raw->vertical_dft; ++ ccdc_hw_params_raw.lens_sh_corr = ++ raw->lens_sh_corr; ++ ccdc_hw_params_raw.data_formatter_r = ++ raw->data_formatter_r; ++ ccdc_hw_params_raw.color_space_con = ++ raw->color_space_con; ++ ccdc_hw_params_raw.col_pat_field0 = ++ raw->col_pat_field0; ++ ccdc_hw_params_raw.col_pat_field1 = ++ raw->col_pat_field1; ++ ++ return 0; ++} ++ ++static int ccdc_update_ycbcr_params(void *arg) ++{ ++ if (copy_from_user(&ccdc_hw_params_ycbcr, ++ (struct ccdc_params_ycbcr *)arg, ++ sizeof(struct ccdc_params_ycbcr))) { ++ dev_err(dev, "ccdc_update_ycbcr_params: error" ++ "in copying ccdc params\n"); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++/* Parameter operations */ ++static int ccdc_setparams(void *params) ++{ ++ int x; ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ x = copy_from_user(&ccdc_hw_params_raw_temp, ++ (struct ccdc_config_params_raw *)params, ++ sizeof(struct ccdc_config_params_raw)); ++ if (x) { ++ dev_err(dev, "ccdc_setparams: error in copying ccdc" ++ "params, %d\n", x); ++ return -EFAULT; ++ } ++ ++ if (!validate_ccdc_param(&ccdc_hw_params_raw_temp)) { ++ if (!ccdc_update_raw_params(&ccdc_hw_params_raw_temp)) ++ return 0; ++ } ++ } else ++ return ccdc_update_ycbcr_params(params); ++ return -EINVAL; ++} ++ ++ ++/*This function will configure CCDC for YCbCr parameters*/ ++static void ccdc_config_ycbcr(void) ++{ ++ u32 modeset; ++ struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; ++ ++ /* first reset the CCDC */ ++ /* all registers have default values after reset */ ++ /* This is important since we assume default values to be set in */ ++ /* a lot of registers that we didn't touch */ ++ dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); ++ ccdc_reset(); ++ ++ /* configure pixel format */ ++ modeset = (params->pix_fmt & 0x3) << 12; ++ ++ /* configure video frame format */ ++ modeset |= (params->frm_fmt & 0x1) << 7; ++ ++ /* setup BT.656 sync mode */ ++ if (params->bt656_enable) { ++ regw(3, REC656IF); ++ /* configure the FID, VD, HD pin polarity */ ++ /* fld,hd pol positive, vd negative, 8-bit pack mode */ ++ modeset |= 0x04; ++ } else { /* y/c external sync mode */ ++ modeset |= ((params->fid_pol & 0x1) << 4); ++ modeset |= ((params->hd_pol & 0x1) << 3); ++ modeset |= ((params->vd_pol & 0x1) << 2); ++ } ++ ++ /* pack the data to 8-bit */ ++ modeset |= 0x1 << 11; ++ ++ regw(modeset, MODESET); ++ ++ /* configure video window */ ++ ccdc_setwin(¶ms->win, params->frm_fmt, 2); ++ /* configure the order of y cb cr in SD-RAM */ ++ regw((params->pix_order << 11) | 0x8040, CCDCFG); ++ ++ /* configure the horizontal line offset */ ++ /* this is done by rounding up width to a multiple of 16 pixels */ ++ /* and multiply by two to account for y:cb:cr 4:2:2 data */ ++ regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); ++ ++ /* configure the memory line offset */ ++ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { ++ /* two fields are interleaved in memory */ ++ regw(0x00000249, SDOFST); ++ } ++ ++ dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); ++} ++ ++ ++/* ++ * ======== ccdc_config_raw ======== ++ * ++ * This function will configure CCDC for Raw mode parameters ++ */ ++static void ccdc_config_raw(void) ++{ ++ struct ccdc_params_raw *params = &ccdc_hw_params_raw; ++ unsigned int mode_set = 0; ++ unsigned int val = 0, val1 = 0; ++ int temp1 = 0, temp2 = 0, i = 0, fmtreg_v = 0, shift_v = 0, flag = 0; ++ int temp_gf = 0, temp_lcs = 0; ++ dev_dbg(dev, "\nStarting ccdc_config_raw..."); ++ /* Reset CCDC */ ++ ccdc_reset(); ++ ++ /* ++ * C O N F I G U R I N G T H E C C D C F G R E G I S T E R ++ */ ++ ++ /*Set CCD Not to swap input since input is RAW data */ ++ val |= CCDC_YCINSWP_RAW; ++ ++ /*set FID detection function to Latch at V-Sync */ ++ val |= CCDC_CCDCFG_FIDMD_LATCH_VSYNC << CCDC_CCDCFG_FIDMD_SHIFT; ++ ++ /*set WENLOG - ccdc valid area */ ++ val |= CCDC_CCDCFG_WENLOG_AND << CCDC_CCDCFG_WENLOG_SHIFT; ++ ++ /*set TRGSEL */ ++ val |= CCDC_CCDCFG_TRGSEL_WEN << CCDC_CCDCFG_TRGSEL_SHIFT; ++ ++ /*set EXTRG */ ++ val |= CCDC_CCDCFG_EXTRG_DISABLE << CCDC_CCDCFG_EXTRG_SHIFT; ++ ++ /* Disable latching function registers on VSYNC-busy writable ++ registers */ ++ ++ /* Enable latching function registers on VSYNC-shadowed registers */ ++ val |= CCDC_LATCH_ON_VSYNC_DISABLE; ++ regw(val, CCDCFG); ++ /* ++ * C O N F I G U R I N G T H E M O D E S E T R E G I S T E R ++ */ ++ ++ /*Set VDHD direction to input */ ++ mode_set |= ++ (CCDC_VDHDOUT_INPUT & CCDC_VDHDOUT_MASK) << CCDC_VDHDOUT_SHIFT; ++ ++ /*Set input type to raw input */ ++ mode_set |= ++ (CCDC_RAW_IP_MODE & CCDC_RAW_INPUT_MASK) << CCDC_RAW_INPUT_SHIFT; ++ ++ /* Configure the vertical sync polarity(MODESET.VDPOL) */ ++ mode_set = (params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT; ++ ++ /* Configure the horizontal sync polarity (MODESET.HDPOL) */ ++ mode_set |= (params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT; ++ ++ /* Configure frame id polarity (MODESET.FLDPOL) */ ++ mode_set |= (params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT; ++ ++ /* Configure data polarity */ ++ mode_set |= ++ (CCDC_DATAPOL_NORMAL & CCDC_DATAPOL_MASK) << CCDC_DATAPOL_SHIFT; ++ ++ /* Configure External WEN Selection */ ++ mode_set |= (CCDC_EXWEN_DISABLE & CCDC_EXWEN_MASK) << CCDC_EXWEN_SHIFT; ++ ++ /* Configure frame format(progressive or interlace) */ ++ mode_set |= (params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT; ++ ++ /* Configure pixel format (Input mode) */ ++ mode_set |= (params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT; ++ ++ if ((params->data_sz == _8BITS) || params->alaw.b_alaw_enable) ++ mode_set |= CCDC_DATA_PACK_ENABLE; ++ ++ /* Configure for LPF */ ++ if (params->lpf_enable) ++ mode_set |= (params->lpf_enable & CCDC_LPF_MASK) << ++ CCDC_LPF_SHIFT; ++ /* Configure the data shift */ ++ mode_set |= (params->datasft & CCDC_DATASFT_MASK) << CCDC_DATASFT_SHIFT; ++ regw(mode_set, MODESET); ++ dev_dbg(dev, "\nWriting 0x%x to MODESET...\n", mode_set); ++ ++ /* Configure the Median Filter threshold */ ++ regw((params->med_filt_thres) & 0x3fff, MEDFILT); ++ ++ /* ++ * C O N F I G U R E T H E G A M M A W D R E G I S T E R ++ */ ++ ++ val = 8; ++ val |= ++ (CCDC_CFA_MOSAIC & CCDC_GAMMAWD_CFA_MASK) << CCDC_GAMMAWD_CFA_SHIFT; ++ ++ /* Enable and configure aLaw register if needed */ ++ if (params->alaw.b_alaw_enable) { ++ val |= (params->alaw.gama_wd & CCDC_ALAW_GAMA_WD_MASK) << 2; ++ val |= CCDC_ALAW_ENABLE; /*set enable bit of alaw */ ++ } ++ ++ /* Configure Median filter1 for IPIPE capture */ ++ val |= params->mfilt1 << CCDC_MFILT1_SHIFT; ++ ++ /* Configure Median filter2 for SDRAM capture */ ++ val |= params->mfilt2 << CCDC_MFILT2_SHIFT; ++ ++ regw(val, GAMMAWD); ++ dev_dbg(dev, "\nWriting 0x%x to GAMMAWD...\n", val); ++ ++ /* configure video window */ ++ ccdc_setwin(¶ms->win, params->frm_fmt, 1); ++ ++ /* ++ * O P T I C A L B L A C K A V E R A G I N G ++ */ ++ val = 0; ++ if (params->blk_clamp.b_clamp_enable) { ++ val |= (params->blk_clamp.start_pixel & CCDC_BLK_ST_PXL_MASK); ++ ++ /* No of line to be avg */ ++ val1 |= (params->blk_clamp.sample_ln & CCDC_NUM_LINE_CALC_MASK) ++ << CCDC_NUM_LINE_CALC_SHIFT; ++ /* No of pixel/line to be avg */ ++ val |= ++ (params->blk_clamp.sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) ++ << CCDC_BLK_SAMPLE_LN_SHIFT; ++ /* Enable the Black clamping */ ++ val |= CCDC_BLK_CLAMP_ENABLE; ++ regw(val, CLAMP); ++ ++ dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val); ++ /* If Black clamping is enable then make dcsub 0 */ ++ regw(val1, DCSUB); ++ dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n"); ++ ++ } else { ++ /* configure DCSub */ ++ val = (params->blk_clamp.dc_sub) & CCDC_BLK_DC_SUB_MASK; ++ regw(val, DCSUB); ++ ++ dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val); ++ regw(0x0000, CLAMP); ++ ++ dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n"); ++ } ++ ++ /* ++ * C O N F I G U R E B L A C K L E V E L C O M P E N S A T I O N ++ */ ++ val = 0; ++ val = (params->blk_comp.b_comp & CCDC_BLK_COMP_MASK); ++ val |= (params->blk_comp.gb_comp & CCDC_BLK_COMP_MASK) ++ << CCDC_BLK_COMP_GB_COMP_SHIFT; ++ regw(val, BLKCMP1); ++ ++ val1 = 0; ++ val1 |= (params->blk_comp.gr_comp & CCDC_BLK_COMP_MASK) ++ << CCDC_BLK_COMP_GR_COMP_SHIFT; ++ val1 |= (params->blk_comp.r_comp & CCDC_BLK_COMP_MASK) ++ << CCDC_BLK_COMP_R_COMP_SHIFT; ++ regw(val1, BLKCMP0); ++ ++ dev_dbg(dev, "\nWriting 0x%x to BLKCMP1...\n", val); ++ dev_dbg(dev, "\nWriting 0x%x to BLKCMP0...\n", val1); ++ ++ /* Configure Vertical Defect Correction if needed */ ++ if (params->vertical_dft.ver_dft_en) { ++ ++ shift_v = 0; ++ shift_v = 0 << CCDC_DFCCTL_VDFCEN_SHIFT; ++ shift_v |= ++ params->vertical_dft.gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; ++ shift_v |= ++ (params->vertical_dft.dft_corr_ctl. ++ vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << ++ CCDC_DFCCTL_VDFCSL_SHIFT; ++ shift_v |= ++ (params->vertical_dft.dft_corr_ctl. ++ vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << ++ CCDC_DFCCTL_VDFCUDA_SHIFT; ++ shift_v |= ++ (params->vertical_dft.dft_corr_ctl. ++ vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << ++ CCDC_DFCCTL_VDFLSFT_SHIFT; ++ regw(shift_v, DFCCTL); ++ regw(params->vertical_dft.dft_corr_vert[0], DFCMEM0); ++ regw(params->vertical_dft.dft_corr_horz[0], DFCMEM1); ++ regw(params->vertical_dft.dft_corr_sub1[0], DFCMEM2); ++ regw(params->vertical_dft.dft_corr_sub2[0], DFCMEM3); ++ regw(params->vertical_dft.dft_corr_sub3[0], DFCMEM4); ++ ++ shift_v = 0; ++ shift_v = regr(DFCMEMCTL); ++ shift_v |= 1 << CCDC_DFCMEMCTL_DFCMARST_SHIFT; ++ shift_v |= 1; ++ regw(shift_v, DFCMEMCTL); ++ ++ while (1) { ++ flag = regr(DFCMEMCTL); ++ if ((flag & 0x01) == 0x00) ++ break; ++ } ++ flag = 0; ++ shift_v = 0; ++ shift_v = regr(DFCMEMCTL); ++ shift_v |= 0 << CCDC_DFCMEMCTL_DFCMARST_SHIFT; ++ regw(shift_v, DFCMEMCTL); ++ ++ for (i = 1; i < 16; i++) { ++ regw(params->vertical_dft.dft_corr_vert[i], DFCMEM0); ++ regw(params->vertical_dft.dft_corr_horz[i], DFCMEM1); ++ regw(params->vertical_dft.dft_corr_sub1[i], DFCMEM2); ++ regw(params->vertical_dft.dft_corr_sub2[i], DFCMEM3); ++ regw(params->vertical_dft.dft_corr_sub3[i], DFCMEM4); ++ ++ shift_v = 0; ++ shift_v = regr(DFCMEMCTL); ++ shift_v |= 1; ++ regw(shift_v, DFCMEMCTL); ++ ++ while (1) { ++ flag = regr(DFCMEMCTL); ++ if ((flag & 0x01) == 0x00) ++ break; ++ } ++ flag = 0; ++ } ++ regw(params->vertical_dft. ++ saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); ++ ++ shift_v = 0; ++ shift_v = regr(DFCCTL); ++ shift_v |= 1 << CCDC_DFCCTL_VDFCEN_SHIFT; ++ regw(shift_v, DFCCTL); ++ } ++ ++ /* Configure Lens Shading Correction if needed */ ++ if (params->lens_sh_corr.lsc_enable) { ++ dev_dbg(dev, "\nlens shading Correction entered....\n"); ++ ++ /* first disable the LSC */ ++ regw(CCDC_LSC_DISABLE, LSCCFG1); ++ ++ /* UPDATE PROCEDURE FOR GAIN FACTOR TABLE 1 */ ++ ++ /* select table 1 */ ++ regw(CCDC_LSC_TABLE1_SLC, LSCMEMCTL); ++ ++ /* Reset memory address */ ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_MEMADDR_RESET; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ /* Update gainfactor for table 1 - u8q8 */ ++ temp_gf = ++ ((int)(params->lens_sh_corr.gf_table1[0].frac_no * 256)) ++ & CCDC_LSC_FRAC_MASK_T1; ++ temp_gf |= ++ (((int)(params->lens_sh_corr.gf_table1[0].frac_no * 256)) ++ & CCDC_LSC_FRAC_MASK_T1) << 8; ++ regw(temp_gf, LSCMEMD); ++ ++ while (1) { ++ if ((regr(LSCMEMCTL) & 0x10) == 0) ++ break; ++ } ++ ++ /* set the address to incremental mode */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_MEMADDR_INCR; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ for (i = 2; i < 255; i += 2) { ++ temp_gf = 0; ++ temp_gf = ((int) ++ (params->lens_sh_corr.gf_table1[0].frac_no * ++ 256)) ++ & CCDC_LSC_FRAC_MASK_T1; ++ temp_gf |= (((int) ++ (params->lens_sh_corr.gf_table1[0]. ++ frac_no * 256)) ++ & CCDC_LSC_FRAC_MASK_T1) << 8; ++ regw(temp_gf, LSCMEMD); ++ ++ while (1) { ++ if ((regr(LSCMEMCTL) & 0x10) == 0) ++ break; ++ } ++ } ++ ++ /* UPDATE PROCEDURE FOR GAIN FACTOR TABLE 2 */ ++ ++ /* select table 2 */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_TABLE2_SLC; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ /*Reset memory address */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_MEMADDR_RESET; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ /*Update gainfactor for table 2 - u16q14 */ ++ temp_gf = ++ (params->lens_sh_corr.gf_table2[0]. ++ int_no & CCDC_LSC_INT_MASK) << 14; ++ temp_gf |= ++ ((int)(params->lens_sh_corr.gf_table2[0].frac_no) * 16384) ++ & CCDC_LSC_FRAC_MASK; ++ regw(temp_gf, LSCMEMD); ++ ++ while (1) { ++ if ((regr(LSCMEMCTL) & 0x10) == 0) ++ break; ++ } ++ ++ /*set the address to incremental mode */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_MEMADDR_INCR; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ for (i = 1; i < 128; i++) { ++ temp_gf = 0; ++ temp_gf = ++ (params->lens_sh_corr.gf_table2[i]. ++ int_no & CCDC_LSC_INT_MASK) << 14; ++ temp_gf |= ++ ((int)(params->lens_sh_corr.gf_table2[0].frac_no) * ++ 16384) ++ & CCDC_LSC_FRAC_MASK; ++ regw(temp_gf, LSCMEMD); ++ ++ while (1) { ++ if ((regr(LSCMEMCTL) & 0x10) == 0) ++ break; ++ } ++ } ++ ++ /*UPDATE PROCEDURE FOR GAIN FACTOR TABLE 3 */ ++ ++ /*select table 3 */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_TABLE3_SLC; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ /*Reset memory address */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_MEMADDR_RESET; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ /*Update gainfactor for table 2 - u16q14 */ ++ temp_gf = ++ (params->lens_sh_corr.gf_table3[0]. ++ int_no & CCDC_LSC_INT_MASK) << 14; ++ temp_gf |= ++ ((int)(params->lens_sh_corr.gf_table3[0].frac_no) * 16384) ++ & CCDC_LSC_FRAC_MASK; ++ regw(temp_gf, LSCMEMD); ++ ++ while (1) { ++ if ((regr(LSCMEMCTL) & 0x10) == 0) ++ break; ++ } ++ ++ /*set the address to incremental mode */ ++ temp_lcs = 0; ++ temp_lcs = regr(LSCMEMCTL); ++ temp_lcs |= CCDC_LSC_MEMADDR_INCR; ++ regw(temp_lcs, LSCMEMCTL); ++ ++ for (i = 1; i < 128; i++) { ++ temp_gf = 0; ++ temp_gf = ++ (params->lens_sh_corr.gf_table3[i]. ++ int_no & CCDC_LSC_INT_MASK) << 14; ++ temp_gf |= ++ ((int)(params->lens_sh_corr.gf_table3[0].frac_no) * ++ 16384) ++ & CCDC_LSC_FRAC_MASK; ++ regw(temp_gf, LSCMEMD); ++ ++ while (1) { ++ if ((regr(LSCMEMCTL) & 0x10) == 0) ++ break; ++ } ++ } ++ /*Configuring the optical centre of the lens */ ++ regw(params->lens_sh_corr. ++ lens_center_horz & CCDC_LSC_CENTRE_MASK, LSCH0); ++ regw(params->lens_sh_corr. ++ lens_center_vert & CCDC_LSC_CENTRE_MASK, LSCV0); ++ ++ val = 0; ++ val = ++ ((int)(params->lens_sh_corr.horz_left_coef.frac_no * 128)) & ++ 0x7f; ++ val |= (params->lens_sh_corr.horz_left_coef.int_no & 0x01) << 7; ++ val |= ++ (((int)(params->lens_sh_corr.horz_right_coef.frac_no * 128)) ++ & 0x7f) << 8; ++ val |= ++ (params->lens_sh_corr.horz_right_coef.int_no & 0x01) << 15; ++ regw(val, LSCKH); ++ ++ val = 0; ++ val = ++ ((int)(params->lens_sh_corr.ver_up_coef.frac_no * 128)) & ++ 0x7f; ++ val |= (params->lens_sh_corr.ver_up_coef.int_no & 0x01) << 7; ++ val |= ++ (((int)(params->lens_sh_corr.ver_low_coef.frac_no * 128)) & ++ 0x7f) << 8; ++ val |= (params->lens_sh_corr.ver_low_coef.int_no & 0x01) << 15; ++ regw(val, LSCKV); ++ ++ /*configuring the lsc configuration register 2 */ ++ temp_lcs = 0; ++ temp_lcs |= ++ (params->lens_sh_corr.lsc_config. ++ gf_table_scaling_fact & CCDC_LSCCFG_GFTSF_MASK) << ++ CCDC_LSCCFG_GFTSF_SHIFT; ++ temp_lcs |= ++ (params->lens_sh_corr.lsc_config. ++ gf_table_interval & CCDC_LSCCFG_GFTINV_MASK) << ++ CCDC_LSCCFG_GFTINV_SHIFT; ++ temp_lcs |= ++ (params->lens_sh_corr.lsc_config. ++ epel & CCDC_LSC_GFTABLE_SEL_MASK) << ++ CCDC_LSC_GFTABLE_EPEL_SHIFT; ++ temp_lcs |= ++ (params->lens_sh_corr.lsc_config. ++ opel & CCDC_LSC_GFTABLE_SEL_MASK) << ++ CCDC_LSC_GFTABLE_OPEL_SHIFT; ++ temp_lcs |= ++ (params->lens_sh_corr.lsc_config. ++ epol & CCDC_LSC_GFTABLE_SEL_MASK) << ++ CCDC_LSC_GFTABLE_EPOL_SHIFT; ++ temp_lcs |= ++ (params->lens_sh_corr.lsc_config. ++ opol & CCDC_LSC_GFTABLE_SEL_MASK) << ++ CCDC_LSC_GFTABLE_OPOL_SHIFT; ++ regw(temp_lcs, LSCCFG2); ++ ++ /*configuring the LSC configuration register 1 */ ++ temp_lcs = 0; ++ temp_lcs |= CCDC_LSC_ENABLE; ++ temp_lcs |= (params->lens_sh_corr.lsc_config.mode & ++ CCDC_LSC_GFMODE_MASK) << CCDC_LSC_GFMODE_SHIFT; ++ regw(temp_lcs, LSCCFG1); ++ } ++ ++ /* Configure data formatter if needed */ ++ if (params->data_formatter_r.fmt_enable ++ && (!params->color_space_con.csc_enable)) { ++ dev_dbg(dev, ++ "\ndata formatter will be configured now....\n"); ++ ++ /*Configuring the FMTPLEN */ ++ fmtreg_v = 0; ++ fmtreg_v |= ++ (params->data_formatter_r.plen. ++ plen0 & CCDC_FMTPLEN_P0_MASK); ++ fmtreg_v |= ++ ((params->data_formatter_r.plen. ++ plen1 & CCDC_FMTPLEN_P1_MASK) ++ << CCDC_FMTPLEN_P1_SHIFT); ++ fmtreg_v |= ++ ((params->data_formatter_r.plen. ++ plen2 & CCDC_FMTPLEN_P2_MASK) ++ << CCDC_FMTPLEN_P2_SHIFT); ++ fmtreg_v |= ++ ((params->data_formatter_r.plen. ++ plen3 & CCDC_FMTPLEN_P3_MASK) ++ << CCDC_FMTPLEN_P3_SHIFT); ++ regw(fmtreg_v, FMTPLEN); ++ ++ /*Configurring the FMTSPH */ ++ regw((params->data_formatter_r.fmtsph & CCDC_FMTSPH_MASK), ++ FMTSPH); ++ ++ /*Configurring the FMTLNH */ ++ regw((params->data_formatter_r.fmtlnh & CCDC_FMTLNH_MASK), ++ FMTLNH); ++ ++ /*Configurring the FMTSLV */ ++ regw((params->data_formatter_r.fmtslv & CCDC_FMTSLV_MASK), ++ FMTSLV); ++ ++ /*Configurring the FMTLNV */ ++ regw((params->data_formatter_r.fmtlnv & CCDC_FMTLNV_MASK), ++ FMTLNV); ++ ++ /*Configurring the FMTRLEN */ ++ regw((params->data_formatter_r.fmtrlen & CCDC_FMTRLEN_MASK), ++ FMTRLEN); ++ ++ /*Configurring the FMTHCNT */ ++ regw((params->data_formatter_r.fmthcnt & CCDC_FMTHCNT_MASK), ++ FMTHCNT); ++ ++ /*Configuring the FMTADDR_PTR */ ++ for (i = 0; i < 8; i++) { ++ fmtreg_v = 0; ++ ++ if (params->data_formatter_r.addr_ptr[i].init > ++ (params->data_formatter_r.fmtrlen - 1)) { ++ dev_dbg(dev, "\nInvalid init parameter for" ++ "FMTADDR_PTR....\n"); ++ return; ++ } ++ ++ fmtreg_v = ++ (params->data_formatter_r.addr_ptr[i]. ++ init & CCDC_ADP_INIT_MASK); ++ fmtreg_v |= ++ ((params->data_formatter_r.addr_ptr[i]. ++ line & CCDC_ADP_LINE_MASK) << ++ CCDC_ADP_LINE_SHIFT); ++ regw(fmtreg_v, FMT_ADDR_PTR(i)); ++ } ++ ++ /* Configuring the FMTPGM_VF0 */ ++ fmtreg_v = 0; ++ for (i = 0; i < 16; i++) ++ fmtreg_v |= params->data_formatter_r.pgm_en[i] << i; ++ regw(fmtreg_v, FMTPGM_VF0); ++ ++ /* Configuring the FMTPGM_VF1 */ ++ fmtreg_v = 0; ++ for (i = 16; i < 32; i++) { ++ fmtreg_v |= ++ params->data_formatter_r.pgm_en[i] << (i - 16); ++ } ++ regw(fmtreg_v, FMTPGM_VF1); ++ ++ /* Configuring the FMTPGM_AP0 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 0; i < 4; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP0); ++ ++ /* Configuring the FMTPGM_AP1 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 4; i < 8; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP1); ++ ++ /* Configuring the FMTPGM_AP2 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 8; i < 12; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP2); ++ ++ /* Configuring the FMTPGM_AP3 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 12; i < 16; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP3); ++ ++ /* Configuring the FMTPGM_AP4 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 16; i < 20; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP4); ++ ++ /* Configuring the FMTPGM_AP5 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 20; i < 24; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP5); ++ ++ /* Configuring the FMTPGM_AP6 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 24; i < 28; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP6); ++ ++ /* Configuring the FMTPGM_AP7 */ ++ fmtreg_v = 0; ++ shift_v = 0; ++ for (i = 28; i < 32; i++) { ++ fmtreg_v |= ++ ((params->data_formatter_r.pgm_ap[i]. ++ pgm_aptr & CCDC_FMTPGN_APTR_MASK) << shift_v); ++ fmtreg_v |= ++ (params->data_formatter_r.pgm_ap[i]. ++ pgmupdt << (shift_v + 3)); ++ shift_v += 4; ++ } ++ regw(fmtreg_v, FMTPGM_AP7); ++ ++ /* Configuring the FMTCFG register */ ++ fmtreg_v = 0; ++ fmtreg_v = CCDC_DF_ENABLE; ++ fmtreg_v |= ++ ((params->data_formatter_r.cfg. ++ mode & CCDC_FMTCFG_FMTMODE_MASK) ++ << CCDC_FMTCFG_FMTMODE_SHIFT); ++ fmtreg_v |= ++ ((params->data_formatter_r.cfg. ++ lnum & CCDC_FMTCFG_LNUM_MASK) ++ << CCDC_FMTCFG_LNUM_SHIFT); ++ fmtreg_v |= ++ ((params->data_formatter_r.cfg. ++ addrinc & CCDC_FMTCFG_ADDRINC_MASK) ++ << CCDC_FMTCFG_ADDRINC_SHIFT); ++ regw(fmtreg_v, FMTCFG); ++ ++ } else if (params->data_formatter_r.fmt_enable) { ++ dev_dbg(dev, ++ "\nCSC and Data Formatter Enabled at same time....\n"); ++ } ++ ++ /* ++ * C O N F I G U R E C O L O R S P A C E C O N V E R T E R ++ */ ++ ++ if ((params->color_space_con.csc_enable) ++ && (!params->data_formatter_r.fmt_enable)) { ++ dev_dbg(dev, "\nconfiguring the CSC Now....\n"); ++ ++ /* Enable the CSC sub-module */ ++ regw(CCDC_CSC_ENABLE, CSCCTL); ++ ++ /* Converting the co-eff as per the format of the register */ ++ for (i = 0; i < 16; i++) { ++ temp1 = params->color_space_con.csc_dec_coeff[i]; ++ /* Masking the data for 3 bits */ ++ temp1 &= CCDC_CSC_COEFF_DEC_MASK; ++ /* Recovering the fractional part and converting to ++ * binary of 5 bits ++ */ ++ temp2 = ++ (int)(params->color_space_con.csc_frac_coeff[i] * ++ (32 / 10)); ++ temp2 &= CCDC_CSC_COEFF_FRAC_MASK; ++ /* shifting the decimal to the MSB */ ++ temp1 = temp1 << CCDC_CSC_DEC_SHIFT; ++ temp1 |= temp2; ++ params->color_space_con.csc_dec_coeff[i] = temp1; ++ } ++ regw(params->color_space_con.csc_dec_coeff[0], CSCM0); ++ regw(params->color_space_con. ++ csc_dec_coeff[1] << CCDC_CSC_COEFF_SHIFT, CSCM0); ++ regw(params->color_space_con.csc_dec_coeff[2], CSCM1); ++ regw(params->color_space_con. ++ csc_dec_coeff[3] << CCDC_CSC_COEFF_SHIFT, CSCM1); ++ regw(params->color_space_con.csc_dec_coeff[4], CSCM2); ++ regw(params->color_space_con. ++ csc_dec_coeff[5] << CCDC_CSC_COEFF_SHIFT, CSCM2); ++ regw(params->color_space_con.csc_dec_coeff[6], CSCM3); ++ regw(params->color_space_con. ++ csc_dec_coeff[7] << CCDC_CSC_COEFF_SHIFT, CSCM3); ++ regw(params->color_space_con.csc_dec_coeff[8], CSCM4); ++ regw(params->color_space_con. ++ csc_dec_coeff[9] << CCDC_CSC_COEFF_SHIFT, CSCM4); ++ regw(params->color_space_con.csc_dec_coeff[10], CSCM5); ++ regw(params->color_space_con. ++ csc_dec_coeff[11] << CCDC_CSC_COEFF_SHIFT, CSCM5); ++ regw(params->color_space_con.csc_dec_coeff[12], CSCM6); ++ regw(params->color_space_con. ++ csc_dec_coeff[13] << CCDC_CSC_COEFF_SHIFT, CSCM6); ++ regw(params->color_space_con.csc_dec_coeff[14], CSCM7); ++ regw(params->color_space_con. ++ csc_dec_coeff[15] << CCDC_CSC_COEFF_SHIFT, CSCM7); ++ ++ } else if (params->color_space_con.csc_enable) { ++ dev_dbg(dev, ++ "\nCSC and Data Formatter Enabled at same time....\n"); ++ } ++ ++ /* Configure the Gain & offset control */ ++ ccdc_config_gain_offset(); ++ ++ /* ++ * C O N F I G U R E C O L O R P A T T E R N A S ++ * P E R N N 1 2 8 6 A S E N S O R ++ */ ++ ++ val = (params->col_pat_field0.olop); ++ val |= (params->col_pat_field0.olep << 2); ++ val |= (params->col_pat_field0.elop << 4); ++ val |= (params->col_pat_field0.elep << 6); ++ val |= (params->col_pat_field1.olop << 8); ++ val |= (params->col_pat_field1.olep << 10); ++ val |= (params->col_pat_field1.elop << 12); ++ val |= (params->col_pat_field1.elep << 14); ++ regw(val, COLPTN); ++ ++ dev_dbg(dev, "\nWriting %x to COLPTN...\n", val); ++ ++ /* ++ * C O N F I G U R I N G T H E H S I Z E R E G I S T E R ++ */ ++ val = 0; ++ val |= ++ (params->data_offset_s. ++ horz_offset & CCDC_DATAOFST_MASK) << CCDC_DATAOFST_H_SHIFT; ++ val |= ++ (params->data_offset_s. ++ vert_offset & CCDC_DATAOFST_MASK) << CCDC_DATAOFST_V_SHIFT; ++ regw(val, DATAOFST); ++ ++ /* ++ * C O N F I G U R I N G T H E H S I Z E R E G I S T E R ++ */ ++ val = 0; ++ val |= ++ (params-> ++ horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << CCDC_HSIZE_FLIP_SHIFT; ++ ++ /* If pack 8 is enable then 1 pixel will take 1 byte */ ++ if ((params->data_sz == _8BITS) || params->alaw.b_alaw_enable) { ++ val |= (((params->win.width) + 31) >> 5) & 0x0fff; ++ ++ dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", ++ (((params->win.width) + 31) >> 5) & 0x0fff); ++ } else { ++ /* else one pixel will take 2 byte */ ++ val |= (((params->win.width * 2) + 31) >> 5) & 0x0fff; ++ ++ dev_dbg(dev, "\nWriting 0x%x to HSIZE...\n", ++ (((params->win.width * 2) + 31) >> 5) & 0x0fff); ++ } ++ regw(val, HSIZE); ++ ++ /* ++ * C O N F I G U R E S D O F S T R E G I S T E R ++ */ ++ ++ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { ++ if (params->image_invert_enable) { ++ /* For interlace inverse mode */ ++ regw(0x4B6D, SDOFST); ++ dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n"); ++ } ++ ++ else { ++ /* For interlace non inverse mode */ ++ regw(0x0B6D, SDOFST); ++ dev_dbg(dev, "\nWriting 0x0B6D to SDOFST...\n"); ++ } ++ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { ++ if (params->image_invert_enable) { ++ /* For progessive inverse mode */ ++ regw(0x4000, SDOFST); ++ dev_dbg(dev, "\nWriting 0x4000 to SDOFST...\n"); ++ } ++ ++ else { ++ /* For progessive non inverse mode */ ++ regw(0x0000, SDOFST); ++ dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n"); ++ } ++ ++ } ++ ++ /* ++ * C O N F I G U R E I N T E R R U P T R E G I S T E R S ++ */ ++ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { ++ val = params->win.height / 2; ++ regw(136, VDINT0); ++ regw(149, VDINT0); ++ regw(0, VDINT1); ++ } else { ++ regw(0, VDINT0); ++ regw(0, VDINT1); ++ } ++ ++ dev_dbg(dev, "\nend of ccdc_config_raw..."); ++} ++ ++static int ccdc_configure(void) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ dev_info(dev, "calling ccdc_config_raw()\n"); ++ ccdc_config_raw(); ++ } else { ++ dev_info(dev, "calling ccdc_config_ycbcr()\n"); ++ ccdc_config_ycbcr(); ++ } ++ return 0; ++} ++ ++static int ccdc_set_buftype(enum ccdc_buftype buf_type) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ ccdc_hw_params_raw.buf_type = buf_type; ++ else ++ ccdc_hw_params_ycbcr.buf_type = buf_type; ++ return 0; ++} ++static int ccdc_get_buftype(enum ccdc_buftype *buf_type) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ *buf_type = ccdc_hw_params_raw.buf_type; ++ else ++ *buf_type = ccdc_hw_params_ycbcr.buf_type; ++ return 0; ++} ++ ++static int ccdc_enum_pix(enum vpfe_hw_pix_format *hw_pix, int i) ++{ ++ int ret = -EINVAL; ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ if (i < CCDC_MAX_RAW_BAYER_FORMATS) { ++ *hw_pix = ccdc_raw_bayer_hw_formats[i]; ++ ret = 0; ++ } ++ } else { ++ if (i < CCDC_MAX_RAW_YUV_FORMATS) { ++ *hw_pix = ccdc_raw_yuv_hw_formats[i]; ++ ret = 0; ++ } ++ } ++ return ret; ++} ++ ++static int ccdc_set_pixel_format(enum vpfe_hw_pix_format pixfmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW; ++ if (pixfmt == VPFE_BAYER_8BIT_PACK_ALAW) ++ ccdc_hw_params_raw.alaw.b_alaw_enable = 1; ++ else if (pixfmt != VPFE_BAYER) ++ return -1; ++ } else { ++ if (pixfmt == VPFE_YUYV) ++ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; ++ else if (pixfmt == VPFE_UYVY) ++ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; ++ else ++ return -1; ++ } ++ return 0; ++} ++static int ccdc_get_pixel_format(enum vpfe_hw_pix_format *pixfmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ if (ccdc_hw_params_raw.alaw.b_alaw_enable) ++ *pixfmt = VPFE_BAYER_8BIT_PACK_ALAW; ++ else ++ *pixfmt = VPFE_BAYER; ++ else { ++ if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) ++ *pixfmt = VPFE_YUYV; ++ else ++ *pixfmt = VPFE_UYVY; ++ } ++ return 0; ++} ++static int ccdc_set_image_window(struct v4l2_rect *win) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ ccdc_hw_params_raw.win.top = win->top; ++ ccdc_hw_params_raw.win.left = win->left; ++ ccdc_hw_params_raw.win.width = win->width; ++ ccdc_hw_params_raw.win.height = win->height; ++ } else { ++ ccdc_hw_params_ycbcr.win.top = win->top; ++ ccdc_hw_params_ycbcr.win.left = win->left; ++ ccdc_hw_params_ycbcr.win.width = win->width; ++ ccdc_hw_params_ycbcr.win.height = win->height; ++ } ++ return 0; ++} ++static int ccdc_get_image_window(struct v4l2_rect *win) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ win->top = ccdc_hw_params_raw.win.top; ++ win->left = ccdc_hw_params_raw.win.left; ++ win->width = ccdc_hw_params_raw.win.width; ++ win->height = ccdc_hw_params_raw.win.height; ++ } else { ++ win->top = ccdc_hw_params_ycbcr.win.top; ++ win->left = ccdc_hw_params_ycbcr.win.left; ++ win->width = ccdc_hw_params_ycbcr.win.width; ++ win->height = ccdc_hw_params_ycbcr.win.height; ++ } ++ return 0; ++} ++static int ccdc_get_line_length(unsigned int *len) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ if ((ccdc_hw_params_raw.alaw.b_alaw_enable) || ++ (ccdc_hw_params_raw.data_sz == _8BITS)) { ++ *len = ccdc_hw_params_raw.win.width; ++ } else { ++ *len = ccdc_hw_params_raw.win.width * 2; ++ } ++ } else { ++ *len = ccdc_hw_params_ycbcr.win.width * 2; ++ } ++ *len = ((*len + 31) & ~0x1f); ++ return 0; ++} ++ ++static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ ccdc_hw_params_raw.frm_fmt = frm_fmt; ++ else ++ ccdc_hw_params_ycbcr.frm_fmt = frm_fmt; ++ return 0; ++} ++static int ccdc_get_frame_format(enum ccdc_frmfmt *frm_fmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ *frm_fmt = ccdc_hw_params_raw.frm_fmt; ++ else ++ *frm_fmt = ccdc_hw_params_ycbcr.frm_fmt; ++ return 0; ++} ++ ++static int ccdc_getfid(void) ++{ ++ int fid = (regr(MODESET) >> 15) & 0x1; ++ return fid; ++} ++ ++/* misc operations */ ++static inline void ccdc_setfbaddr(unsigned long addr) ++{ ++ regw((addr >> 21) & 0x007f, STADRH); ++ regw((addr >> 5) & 0x0ffff, STADRL); ++} ++ ++static int ccdc_set_hw_if_type(enum vpfe_hw_if_type iface) ++{ ++ ccdc_if_type = iface; ++ return 0; ++} ++ ++struct ccdc_hw_device ccdc_hw_dev = { ++ .name = "DM355 CCDC", ++ .set_ccdc_base = ccdc_set_ccdc_base, ++ .set_vpss_base = ccdc_set_vpss_base, ++ .get_ccdc_base = ccdc_get_ccdc_base, ++ .get_vpss_base = ccdc_get_vpss_base, ++ .open = ccdc_open, ++ .enable = ccdc_enable, ++ .enable_out_to_sdram = ccdc_enable_output_to_sdram, ++ .set_hw_if_type = ccdc_set_hw_if_type, ++ .setparams = ccdc_setparams, ++ .configure = ccdc_configure, ++ .set_buftype = ccdc_set_buftype, ++ .get_buftype = ccdc_get_buftype, ++ .enum_pix = ccdc_enum_pix, ++ .set_pixelformat = ccdc_set_pixel_format, ++ .get_pixelformat = ccdc_get_pixel_format, ++ .set_frame_format = ccdc_set_frame_format, ++ .get_frame_format = ccdc_get_frame_format, ++ .set_image_window = ccdc_set_image_window, ++ .get_image_window = ccdc_get_image_window, ++ .get_line_length = ccdc_get_line_length, ++ .queryctrl = ccdc_queryctrl, ++ .setcontrol = ccdc_setcontrol, ++ .getcontrol = ccdc_getcontrol, ++ .setfbaddr = ccdc_setfbaddr, ++ .getfid = ccdc_getfid, ++}; ++EXPORT_SYMBOL(ccdc_hw_dev); ++ ++static int dm355_ccdc_init(void) ++{ ++ return 0; ++} ++ ++static void dm355_ccdc_exit(void) ++{ ++} ++ ++subsys_initcall(dm355_ccdc_init); ++module_exit(dm355_ccdc_exit); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/video/davinci/ccdc_dm355.h b/drivers/media/video/davinci/ccdc_dm355.h +new file mode 100644 +index 0000000..a78349a +--- /dev/null ++++ b/drivers/media/video/davinci/ccdc_dm355.h +@@ -0,0 +1,758 @@ ++/* ++ * Copyright (C) 2005-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef _CCDC_DM355_H ++#define _CCDC_DM355_H ++#include <media/davinci/ccdc_common.h> ++ ++/* Define to enable/disable video port */ ++ ++#define CCDC_WIN_PAL {0, 0, 720, 576} ++#define CCDC_WIN_VGA {0, 0, 640, 480} ++ ++/* enum for No of pixel per line to be avg. in Black Clamping*/ ++enum sample_length { ++ _1PIXELS, ++ _2PIXELS, ++ _4PIXELS, ++ _8PIXELS, ++ _16PIXELS ++}; ++ ++/* enum for No of lines in Black Clamping */ ++enum sample_line { ++ _1LINES, ++ _2LINES, ++ _4LINES, ++ _8LINES, ++ _16LINES ++}; ++ ++/* enum for Alaw gama width */ ++enum gama_width { ++ BITS_13_4, ++ BITS_12_3, ++ BITS_11_2, ++ BITS_10_1, ++ BITS_09_0 ++}; ++ ++enum ccdc_colpats { ++ CCDC_RED, ++ CCDC_GREEN_RED, ++ CCDC_GREEN_BLUE, ++ CCDC_BLUE ++}; ++ ++struct ccdc_col_pat { ++ enum ccdc_colpats olop; ++ enum ccdc_colpats olep; ++ enum ccdc_colpats elop; ++ enum ccdc_colpats elep; ++}; ++ ++enum ccdc_datasft { ++ NO_SHIFT, ++ _1BIT, ++ _2BIT, ++ _3BIT, ++ _4BIT, ++ _5BIT, ++ _6BIT ++}; ++ ++enum data_size { ++ _16BITS, ++ _15BITS, ++ _14BITS, ++ _13BITS, ++ _12BITS, ++ _11BITS, ++ _10BITS, ++ _8BITS ++}; ++enum ccdc_mfilt1 { ++ NO_MEDIAN_FILTER1, ++ AVERAGE_FILTER1, ++ MEDIAN_FILTER1 ++}; ++ ++enum ccdc_mfilt2 { ++ NO_MEDIAN_FILTER2 = 0, ++ AVERAGE_FILTER2, ++ MEDIAN_FILTER2 ++}; ++ ++struct ccdc_imgwin { ++ unsigned int top; ++ unsigned int left; ++ unsigned int width; ++ unsigned int height; ++}; ++ ++/* structure for ALaw */ ++struct ccdc_a_law { ++ /* Enable/disable A-Law */ ++ unsigned char b_alaw_enable; ++ /*Gama Width Input */ ++ enum gama_width gama_wd; ++}; ++ ++/* structure for Black Clamping */ ++struct ccdc_black_clamp { ++ /* only if bClampEnable is TRUE */ ++ unsigned char b_clamp_enable; ++ /* only if bClampEnable is TRUE */ ++ enum sample_length sample_pixel; ++ /* only if bClampEnable is TRUE */ ++ enum sample_line sample_ln; ++ /* only if bClampEnable is TRUE */ ++ unsigned short start_pixel; ++ /* only if bClampEnable is FALSE */ ++ unsigned short sgain; ++ unsigned short dc_sub; ++}; ++ ++/* structure for Black Level Compensation */ ++struct black_compensation { ++ /* Constant value to subtract from Red component */ ++ unsigned char r_comp; ++ /* Constant value to subtract from Gr component */ ++ unsigned char gr_comp; ++ /* Constant value to subtract from Blue component */ ++ unsigned char b_comp; ++ /* Constant value to subtract from Gb component */ ++ unsigned char gb_comp; ++}; ++ ++/*structures for lens shading correction*/ ++ ++/*gain factor modes*/ ++enum gfmode { ++ u8q8_interpol, ++ u16q14_interpol, ++ reserved, ++ u16q14 ++}; ++ ++enum gf_table_sel { ++ table1 = 0, ++ table2, ++ table3 ++}; ++ ++/*LSC configuration structure*/ ++struct lsccfg { ++ enum gfmode mode; ++ int gf_table_scaling_fact; ++ int gf_table_interval; ++ enum gf_table_sel epel; ++ enum gf_table_sel opel; ++ enum gf_table_sel epol; ++ enum gf_table_sel opol; ++}; ++ ++struct float_ccdc { ++ unsigned int int_no; ++ unsigned int frac_no; ++}; ++ ++/*Main structure for lens shading correction*/ ++struct lens_shading_corr { ++ unsigned char lsc_enable; ++ struct lsccfg lsc_config; ++ unsigned int lens_center_horz; ++ unsigned int lens_center_vert; ++ struct float_ccdc horz_left_coef; ++ struct float_ccdc horz_right_coef; ++ struct float_ccdc ver_low_coef; ++ struct float_ccdc ver_up_coef; ++ struct float_ccdc gf_table1[256]; ++ /*int_no will be always 0 since it is u8q8 */ ++ struct float_ccdc gf_table2[128]; ++ struct float_ccdc gf_table3[128]; ++}; ++ ++/*structure for color space converter*/ ++struct color_space_converter { ++ unsigned char csc_enable; ++ int csc_dec_coeff[16]; ++ int csc_frac_coeff[16]; ++}; ++ ++/*supporting structures for data formatter*/ ++enum fmtmode { ++ split, ++ combine, ++ line_alt_mode ++}; ++ ++enum line_num { ++ _1line, ++ _2lines, ++ _3lines, ++ _4lines ++}; ++ ++enum line_pos { ++ _1stline, ++ _2ndline, ++ _3rdline, ++ _4thline ++}; ++ ++struct fmtplen { ++ unsigned int plen0; ++ unsigned int plen1; ++ unsigned int plen2; ++ unsigned int plen3; ++}; ++ ++struct fmtcfg { ++ enum fmtmode mode; ++ enum line_num lnum; ++ unsigned int addrinc; ++}; ++ ++struct fmtaddr_ptr { ++ unsigned int init; ++ enum line_pos line; ++}; ++ ++struct fmtpgm_ap { ++ unsigned int pgm_aptr; ++ unsigned char pgmupdt; ++}; ++ ++/* Main Structure for data formatter*/ ++struct data_formatter { ++ unsigned char fmt_enable; ++ struct fmtcfg cfg; ++ struct fmtplen plen; ++ unsigned int fmtsph; ++ unsigned int fmtlnh; ++ unsigned int fmtslv; ++ unsigned int fmtlnv; ++ unsigned int fmtrlen; ++ unsigned int fmthcnt; ++ struct fmtaddr_ptr addr_ptr[8]; ++ unsigned char pgm_en[32]; ++ struct fmtpgm_ap pgm_ap[32]; ++}; ++ ++/* Structures for Vertical Defect Correction*/ ++enum vdf_csl { ++ normal = 0, ++ horz_interpol_sat, ++ horz_interpol ++}; ++ ++enum vdf_cuda { ++ whole_line_correct, ++ upper_disable ++}; ++ ++enum dfc_mwr { ++ write_complete, ++ write_reg ++}; ++ ++enum dfc_mrd { ++ read_complete, ++ read_reg ++}; ++ ++enum dfc_ma_rst { ++ incr_addr, ++ clr_addr ++}; ++ ++enum dfc_mclr { ++ clear_complete, ++ clear ++}; ++ ++struct dft_corr_ctl_s { ++ enum vdf_csl vdfcsl; ++ enum vdf_cuda vdfcuda; ++ unsigned int vdflsft; ++}; ++ ++struct dft_corr_mem_ctl_s { ++ enum dfc_mwr dfcmwr; ++ enum dfc_mrd dfcmrd; ++ enum dfc_ma_rst dfcmarst; ++ enum dfc_mclr dfcmclr; ++}; ++ ++/* Main Structure for vertical defect correction. Vertical defect ++ * correction can correct upto 16 defects if defects less than 16 ++ * then pad the rest with 0 ++ */ ++struct vertical_dft_s { ++ unsigned char ver_dft_en; ++ unsigned char gen_dft_en; ++ unsigned int saturation_ctl; ++ struct dft_corr_ctl_s dft_corr_ctl; ++ struct dft_corr_mem_ctl_s dft_corr_mem_ctl; ++ unsigned int dft_corr_horz[16]; ++ unsigned int dft_corr_vert[16]; ++ unsigned int dft_corr_sub1[16]; ++ unsigned int dft_corr_sub2[16]; ++ unsigned int dft_corr_sub3[16]; ++}; ++ ++struct data_offset { ++ unsigned char horz_offset; ++ unsigned char vert_offset; ++}; ++ ++/* Structure for CCDC configuration parameters for raw capture mode passed ++ * by application ++ */ ++struct ccdc_config_params_raw { ++ /* pixel format */ ++ enum ccdc_pixfmt pix_fmt; ++ /* progressive or interlaced frame */ ++ enum ccdc_frmfmt frm_fmt; ++ /* video window */ ++ struct ccdc_imgwin win; ++ /* field id polarity */ ++ enum ccdc_pinpol fid_pol; ++ /* vertical sync polarity */ ++ enum ccdc_pinpol vd_pol; ++ /* horizontal sync polarity */ ++ enum ccdc_pinpol hd_pol; ++ /* interleaved or separated fields */ ++ enum ccdc_buftype buf_type; ++ /*data shift to be applied before storing */ ++ enum ccdc_datasft datasft; ++ /*median filter for sdram */ ++ enum ccdc_mfilt1 mfilt1; ++ enum ccdc_mfilt2 mfilt2; ++ /*median filter for ipipe */ ++ /*low pass filter enable/disable */ ++ unsigned char lpf_enable; ++ unsigned char horz_flip_enable; ++ /*offset value to be applied to data */ ++ /*Range is 0 to 1023 */ ++ unsigned int ccdc_offset; ++ /*Threshold of median filter */ ++ int med_filt_thres; ++ /* enable to store the image in inverse */ ++ unsigned char image_invert_enable; ++ /* data size value from 8 to 16 bits */ ++ enum data_size data_sz; ++ /*horz and vertical data offset */ ++ struct data_offset data_offset_s; ++ /* Structure for Optional A-Law */ ++ struct ccdc_a_law alaw; ++ /* Structure for Optical Black Clamp */ ++ struct ccdc_black_clamp blk_clamp; ++ /* Structure for Black Compensation */ ++ struct black_compensation blk_comp; ++ /*struture for vertical Defect Correction Module Configuration */ ++ struct vertical_dft_s vertical_dft; ++ /*structure for lens shading Correction Module Configuration */ ++ struct lens_shading_corr lens_sh_corr; ++ /*structure for data formatter Module Configuration */ ++ struct data_formatter data_formatter_r; ++ /*structure for color space converter Module Configuration */ ++ struct color_space_converter color_space_con; ++ struct ccdc_col_pat col_pat_field0; ++ struct ccdc_col_pat col_pat_field1; ++}; ++ ++#ifdef __KERNEL__ ++#include <linux/io.h> ++/* SOC specific controls for Bayer capture. The CIDs ++ * listed here should match with that in davinci_vpfe.h ++ */ ++/* White balance on Bayer RGB. U11Q8 */ ++#define CCDC_CID_R_GAIN (V4L2_CID_PRIVATE_BASE + 0) ++#define CCDC_CID_GR_GAIN (V4L2_CID_PRIVATE_BASE + 1) ++#define CCDC_CID_GB_GAIN (V4L2_CID_PRIVATE_BASE + 2) ++#define CCDC_CID_B_GAIN (V4L2_CID_PRIVATE_BASE + 3) ++/* Offsets */ ++#define CCDC_CID_OFFSET (V4L2_CID_PRIVATE_BASE + 4) ++#define CCDC_CID_MAX (V4L2_CID_PRIVATE_BASE + 5) ++#define CCDC_MAX_CONTROLS 5 ++ ++/* Gain applied to Raw Bayer data */ ++struct ccdc_gain { ++ unsigned short r_ye; ++ unsigned short gr_cy; ++ unsigned short gb_g; ++ unsigned short b_mg; ++}; ++ ++/* Structure for CCDC configuration parameters for raw capture mode */ ++struct ccdc_params_raw { ++ /* pixel format */ ++ enum ccdc_pixfmt pix_fmt; ++ /* progressive or interlaced frame */ ++ enum ccdc_frmfmt frm_fmt; ++ /* video window */ ++ struct ccdc_imgwin win; ++ /* field id polarity */ ++ enum ccdc_pinpol fid_pol; ++ /* vertical sync polarity */ ++ enum ccdc_pinpol vd_pol; ++ /* horizontal sync polarity */ ++ enum ccdc_pinpol hd_pol; ++ /* interleaved or separated fields */ ++ enum ccdc_buftype buf_type; ++ /*data shift to be applied before storing */ ++ enum ccdc_datasft datasft; ++ /*median filter for sdram */ ++ enum ccdc_mfilt1 mfilt1; ++ /*median filter for ipipe */ ++ enum ccdc_mfilt2 mfilt2; ++ /*low pass filter enable/disable */ ++ unsigned char lpf_enable; ++ unsigned char horz_flip_enable; ++ /*offset value to be applied to data */ ++ /*Range is 0 to 1023 */ ++ unsigned int ccdc_offset; ++ /* Gain values */ ++ struct ccdc_gain gain; ++ /*Threshold of median filter */ ++ int med_filt_thres; ++ /* enable to store the image in inverse order in memory ++ * (bottom to top) ++ */ ++ unsigned char image_invert_enable; ++ /* data size value from 8 to 16 bits */ ++ enum data_size data_sz; ++ /* Structure for Optional A-Law */ ++ struct ccdc_a_law alaw; ++ /*horz and vertical data offset */ ++ struct data_offset data_offset_s; ++ /* Structure for Optical Black Clamp */ ++ struct ccdc_black_clamp blk_clamp; ++ /* Structure for Black Compensation */ ++ struct black_compensation blk_comp; ++ /*struture for vertical Defect Correction Module Configuration */ ++ struct vertical_dft_s vertical_dft; ++ /*structure for lens shading Correction Module Configuration */ ++ struct lens_shading_corr lens_sh_corr; ++ /*structure for data formatter Module Configuration */ ++ struct data_formatter data_formatter_r; ++ /*structure for color space converter Module Configuration */ ++ struct color_space_converter color_space_con; ++ struct ccdc_col_pat col_pat_field0; ++ struct ccdc_col_pat col_pat_field1; ++}; ++ ++struct ccdc_params_ycbcr { ++ /* pixel format */ ++ enum ccdc_pixfmt pix_fmt; ++ /* progressive or interlaced frame */ ++ enum ccdc_frmfmt frm_fmt; ++ /* video window */ ++ struct ccdc_imgwin win; ++ /* field id polarity */ ++ enum ccdc_pinpol fid_pol; ++ /* vertical sync polarity */ ++ enum ccdc_pinpol vd_pol; ++ /* horizontal sync polarity */ ++ enum ccdc_pinpol hd_pol; ++ /* enable BT.656 embedded sync mode */ ++ int bt656_enable; ++ /* cb:y:cr:y or y:cb:y:cr in memory */ ++ enum ccdc_pixorder pix_order; ++ /* interleaved or separated fields */ ++ enum ccdc_buftype buf_type; ++}; ++ ++struct ccdc_supported_pix_fmt { ++ int index; ++ unsigned int pix_fmt; ++}; ++ ++/**************************************************************************\ ++* Register OFFSET Definitions ++\**************************************************************************/ ++#define SYNCEN 0x00 ++#define MODESET 0x04 ++#define HDWIDTH 0x08 ++#define VDWIDTH 0x0c ++#define PPLN 0x10 ++#define LPFR 0x14 ++#define SPH 0x18 ++#define NPH 0x1c ++#define SLV0 0x20 ++#define SLV1 0x24 ++#define NLV 0x28 ++#define CULH 0x2c ++#define CULV 0x30 ++#define HSIZE 0x34 ++#define SDOFST 0x38 ++#define STADRH 0x3c ++#define STADRL 0x40 ++#define CLAMP 0x44 ++#define DCSUB 0x48 ++#define COLPTN 0x4c ++#define BLKCMP0 0x50 ++#define BLKCMP1 0x54 ++#define MEDFILT 0x58 ++#define RYEGAIN 0x5c ++#define GRCYGAIN 0x60 ++#define GBGGAIN 0x64 ++#define BMGGAIN 0x68 ++#define OFFSET 0x6c ++#define OUTCLIP 0x70 ++#define VDINT0 0x74 ++#define VDINT1 0x78 ++#define RSV0 0x7c ++#define GAMMAWD 0x80 ++#define REC656IF 0x84 ++#define CCDCFG 0x88 ++#define FMTCFG 0x8c ++#define FMTPLEN 0x90 ++#define FMTSPH 0x94 ++#define FMTLNH 0x98 ++#define FMTSLV 0x9c ++#define FMTLNV 0xa0 ++#define FMTRLEN 0xa4 ++#define FMTHCNT 0xa8 ++#define FMT_ADDR_PTR_B 0xac ++#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i*4)) ++#define FMTPGM_VF0 0xcc ++#define FMTPGM_VF1 0xd0 ++#define FMTPGM_AP0 0xd4 ++#define FMTPGM_AP1 0xd8 ++#define FMTPGM_AP2 0xdc ++#define FMTPGM_AP3 0xe0 ++#define FMTPGM_AP4 0xe4 ++#define FMTPGM_AP5 0xe8 ++#define FMTPGM_AP6 0xec ++#define FMTPGM_AP7 0xf0 ++#define LSCCFG1 0xf4 ++#define LSCCFG2 0xf8 ++#define LSCH0 0xfc ++#define LSCV0 0x100 ++#define LSCKH 0x104 ++#define LSCKV 0x108 ++#define LSCMEMCTL 0x10c ++#define LSCMEMD 0x110 ++#define LSCMEMQ 0x114 ++#define DFCCTL 0x118 ++#define DFCVSAT 0x11c ++#define DFCMEMCTL 0x120 ++#define DFCMEM0 0x124 ++#define DFCMEM1 0x128 ++#define DFCMEM2 0x12c ++#define DFCMEM3 0x130 ++#define DFCMEM4 0x134 ++#define CSCCTL 0x138 ++#define CSCM0 0x13c ++#define CSCM1 0x140 ++#define CSCM2 0x144 ++#define CSCM3 0x148 ++#define CSCM4 0x14c ++#define CSCM5 0x150 ++#define CSCM6 0x154 ++#define CSCM7 0x158 ++#define DATAOFST 0x15c ++ ++#define CLKCTRL (0x04) ++ ++/* offset relative to 0x1c70800 */ ++#define INTSTAT (0xC) ++#define INTSEL (0x10) ++#define EVTSEL (0x14) ++#define MEMCTRL (0x18) ++#define CCDCMUX (0x1C) ++ ++/************************************************************** ++* Define for various register bit mask and shifts for CCDC ++* ++**************************************************************/ ++#define CCDC_RAW_IP_MODE (0x00) ++#define CCDC_VDHDOUT_INPUT (0x00) ++#define CCDC_YCINSWP_RAW (0x00 << 4) ++#define CCDC_EXWEN_DISABLE (0x00) ++#define CCDC_DATAPOL_NORMAL (0x00) ++#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC (0x00) ++#define CCDC_CCDCFG_WENLOG_AND (0x00) ++#define CCDC_CCDCFG_TRGSEL_WEN (0x00) ++#define CCDC_CCDCFG_EXTRG_DISABLE (0x00) ++#define CCDC_CFA_MOSAIC (0x00) ++ ++#define CCDC_VDC_DFCVSAT_MASK (0x3fff) ++#define CCDC_DATAOFST_MASK (0x0ff) ++#define CCDC_DATAOFST_H_SHIFT (0) ++#define CCDC_DATAOFST_V_SHIFT (8) ++#define CCDC_GAMMAWD_CFA_MASK (0x01) ++#define CCDC_GAMMAWD_CFA_SHIFT (5) ++#define CCDC_FID_POL_MASK (0x01) ++#define CCDC_FID_POL_SHIFT (4) ++#define CCDC_HD_POL_MASK (0x01) ++#define CCDC_HD_POL_SHIFT (3) ++#define CCDC_VD_POL_MASK (0x01) ++#define CCDC_VD_POL_SHIFT (2) ++#define CCDC_FRM_FMT_MASK (0x01) ++#define CCDC_FRM_FMT_SHIFT (7) ++#define CCDC_DATA_SZ_MASK (0x07) ++#define CCDC_DATA_SZ_SHIFT (8) ++#define CCDC_VDHDOUT_MASK (0x01) ++#define CCDC_VDHDOUT_SHIFT (0) ++#define CCDC_EXWEN_MASK (0x01) ++#define CCDC_EXWEN_SHIFT (5) ++#define CCDC_RAW_INPUT_MASK (0x03) ++#define CCDC_RAW_INPUT_SHIFT (12) ++#define CCDC_PIX_FMT_MASK (0x03) ++#define CCDC_PIX_FMT_SHIFT (12) ++#define CCDC_DATAPOL_MASK (0x01) ++#define CCDC_DATAPOL_SHIFT (6) ++#define CCDC_WEN_ENABLE (0x01 << 1) ++#define CCDC_VDHDEN_ENABLE (0x01 << 16) ++#define CCDC_LPF_ENABLE (0x01 << 14) ++#define CCDC_ALAW_ENABLE (0x01) ++#define CCDC_ALAW_GAMA_WD_MASK (0x07) ++ ++#define CCDC_FMTCFG_FMTMODE_MASK (0x03) ++#define CCDC_FMTCFG_FMTMODE_SHIFT (1) ++#define CCDC_FMTCFG_LNUM_MASK (0x03) ++#define CCDC_FMTCFG_LNUM_SHIFT (4) ++#define CCDC_FMTCFG_ADDRINC_MASK (0x07) ++#define CCDC_FMTCFG_ADDRINC_SHIFT (8) ++ ++#define CCDC_CCDCFG_FIDMD_SHIFT (6) ++#define CCDC_CCDCFG_WENLOG_SHIFT (8) ++#define CCDC_CCDCFG_TRGSEL_SHIFT (9) ++#define CCDC_CCDCFG_EXTRG_SHIFT (10) ++#define CCDC_CCDCFG_MSBINVI_SHIFT (13) ++ ++#define CCDC_HSIZE_FLIP_SHIFT (12) ++#define CCDC_HSIZE_FLIP_MASK (0x01) ++ ++#define START_PX_HOR_MASK (0x7FFF) ++#define NUM_PX_HOR_MASK (0x7FFF) ++#define START_VER_ONE_MASK (0x7FFF) ++#define START_VER_TWO_MASK (0x7FFF) ++#define NUM_LINES_VER (0x7FFF) ++ ++#define CCDC_BLK_CLAMP_ENABLE (0x01 << 15) ++#define CCDC_BLK_SGAIN_MASK (0x1F) ++#define CCDC_BLK_ST_PXL_MASK (0x1FFF) ++#define CCDC_BLK_SAMPLE_LN_MASK (0x03) ++#define CCDC_BLK_SAMPLE_LN_SHIFT (13) ++ ++#define CCDC_NUM_LINE_CALC_MASK (0x03) ++#define CCDC_NUM_LINE_CALC_SHIFT (14) ++ ++#define CCDC_BLK_DC_SUB_MASK (0x03FFF) ++#define CCDC_BLK_COMP_MASK (0x000000FF) ++#define CCDC_BLK_COMP_GB_COMP_SHIFT (8) ++#define CCDC_BLK_COMP_GR_COMP_SHIFT (0) ++#define CCDC_BLK_COMP_R_COMP_SHIFT (8) ++#define CCDC_LATCH_ON_VSYNC_DISABLE (0x01 << 15) ++#define CCDC_LATCH_ON_VSYNC_ENABLE (0x00 << 15) ++#define CCDC_FPC_ENABLE (0x01 << 15) ++#define CCDC_FPC_FPC_NUM_MASK (0x7FFF) ++#define CCDC_DATA_PACK_ENABLE (0x01 << 11) ++#define CCDC_FMT_HORZ_FMTLNH_MASK (0x1FFF) ++#define CCDC_FMT_HORZ_FMTSPH_MASK (0x1FFF) ++#define CCDC_FMT_HORZ_FMTSPH_SHIFT (16) ++#define CCDC_FMT_VERT_FMTLNV_MASK (0x1FFF) ++#define CCDC_FMT_VERT_FMTSLV_MASK (0x1FFF) ++#define CCDC_FMT_VERT_FMTSLV_SHIFT (16) ++#define CCDC_VP_OUT_VERT_NUM_MASK (0x3FFF) ++#define CCDC_VP_OUT_VERT_NUM_SHIFT (17) ++#define CCDC_VP_OUT_HORZ_NUM_MASK (0x1FFF) ++#define CCDC_VP_OUT_HORZ_NUM_SHIFT (4) ++#define CCDC_VP_OUT_HORZ_ST_MASK (0x000F) ++ ++#define CCDC_CSC_COEFF_SHIFT (8) ++#define CCDC_CSC_COEFF_DEC_MASK (0x0007) ++#define CCDC_CSC_COEFF_FRAC_MASK (0x001F) ++#define CCDC_CSC_DEC_SHIFT (5) ++#define CCDC_CSC_ENABLE (0x01) ++#define CCDC_MFILT1_SHIFT (10) ++#define CCDC_MFILT2_SHIFT (8) ++#define CCDC_LPF_MASK (0x01) ++#define CCDC_LPF_SHIFT (14) ++#define CCDC_OFFSET_MASK (0x3FF) ++#define CCDC_DATASFT_MASK (0x07) ++#define CCDC_DATASFT_SHIFT (8) ++#define CCDC_DF_ENABLE (0x01) ++ ++#define CCDC_FMTPLEN_P0_MASK (0x000F) ++#define CCDC_FMTPLEN_P1_MASK (0x000F) ++#define CCDC_FMTPLEN_P2_MASK (0x0007) ++#define CCDC_FMTPLEN_P3_MASK (0x0007) ++#define CCDC_FMTPLEN_P0_SHIFT (0) ++#define CCDC_FMTPLEN_P1_SHIFT (4) ++#define CCDC_FMTPLEN_P2_SHIFT (8) ++#define CCDC_FMTPLEN_P3_SHIFT (12) ++ ++#define CCDC_FMTSPH_MASK (0x01FFF) ++#define CCDC_FMTLNH_MASK (0x01FFF) ++#define CCDC_FMTSLV_MASK (0x01FFF) ++#define CCDC_FMTLNV_MASK (0x07FFF) ++#define CCDC_FMTRLEN_MASK (0x01FFF) ++#define CCDC_FMTHCNT_MASK (0x01FFF) ++ ++#define CCDC_ADP_INIT_MASK (0x01FFF) ++#define CCDC_ADP_LINE_SHIFT (13) ++#define CCDC_ADP_LINE_MASK (0x0003) ++#define CCDC_FMTPGN_APTR_MASK (0x0007) ++ ++#define CCDC_DFCCTL_GDFCEN_MASK (0x01) ++#define CCDC_DFCCTL_VDFCEN_MASK (0x01) ++#define CCDC_DFCCTL_VDFCEN_SHIFT (4) ++#define CCDC_DFCCTL_VDFCSL_MASK (0x03) ++#define CCDC_DFCCTL_VDFCSL_SHIFT (5) ++#define CCDC_DFCCTL_VDFCUDA_MASK (0x01) ++#define CCDC_DFCCTL_VDFCUDA_SHIFT (7) ++#define CCDC_DFCCTL_VDFLSFT_MASK (0x03) ++#define CCDC_DFCCTL_VDFLSFT_SHIFT (8) ++#define CCDC_DFCMEMCTL_DFCMARST_MASK (0x01) ++#define CCDC_DFCMEMCTL_DFCMARST_SHIFT (2) ++#define CCDC_DFCMEMCTL_DFCMWR_MASK (0x01) ++#define CCDC_DFCMEMCTL_DFCMWR_SHIFT (0) ++ ++#define CCDC_LSCCFG_GFTSF_MASK (0x07) ++#define CCDC_LSCCFG_GFTSF_SHIFT (1) ++#define CCDC_LSCCFG_GFTINV_MASK (0x0f) ++#define CCDC_LSCCFG_GFTINV_SHIFT (4) ++#define CCDC_LSC_GFTABLE_SEL_MASK (0x03) ++#define CCDC_LSC_GFTABLE_EPEL_SHIFT (8) ++#define CCDC_LSC_GFTABLE_OPEL_SHIFT (10) ++#define CCDC_LSC_GFTABLE_EPOL_SHIFT (12) ++#define CCDC_LSC_GFTABLE_OPOL_SHIFT (14) ++#define CCDC_LSC_GFMODE_MASK (0x03) ++#define CCDC_LSC_GFMODE_SHIFT (4) ++#define CCDC_LSC_DISABLE (0) ++#define CCDC_LSC_ENABLE (1) ++#define CCDC_LSC_TABLE1_SLC (0) ++#define CCDC_LSC_TABLE2_SLC (1) ++#define CCDC_LSC_TABLE3_SLC (2) ++#define CCDC_LSC_MEMADDR_RESET (1 << 2) ++#define CCDC_LSC_MEMADDR_INCR (0 << 2) ++#define CCDC_LSC_FRAC_MASK_T1 (0xFF) ++#define CCDC_LSC_INT_MASK (0x03) ++#define CCDC_LSC_FRAC_MASK (0x3FFF) ++#define CCDC_LSC_CENTRE_MASK (0x3FFF) ++#define CCDC_LSC_COEF_MASK (0x0ff) ++#define CCDC_LSC_COEFL_SHIFT (0) ++#define CCDC_LSC_COEFU_SHIFT (8) ++#define CCDC_GAIN_MASK (0x7FF) ++#endif ++#endif /* CCDC_DM355_H */ +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci/vfpe4.patch b/recipes/linux/linux-davinci/vfpe4.patch new file mode 100644 index 0000000000..2e95f9eea4 --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe4.patch @@ -0,0 +1,1660 @@ +Subject: +[PATCH 4/7] ccdc hw module and header file for DM6446 +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:23:16 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Adds ccdc hw module and it's header file + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + drivers/media/video/ccdc_davinci.c | 124 ---- + drivers/media/video/davinci/ccdc_davinci.c | 1007 ++++++++++++++++++++++++++++ + drivers/media/video/davinci/ccdc_davinci.h | 335 +++++++++ + include/media/ccdc_davinci.h | 144 ---- + 4 files changed, 1342 insertions(+), 268 deletions(-) + delete mode 100644 drivers/media/video/ccdc_davinci.c + create mode 100644 drivers/media/video/davinci/ccdc_davinci.c + create mode 100644 drivers/media/video/davinci/ccdc_davinci.h + delete mode 100644 include/media/ccdc_davinci.h + +diff --git a/drivers/media/video/ccdc_davinci.c b/drivers/media/video/ccdc_davinci.c +deleted file mode 100644 +index d3cd333..0000000 +--- a/drivers/media/video/ccdc_davinci.c ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- * +- * +- * Copyright (C) 2006 Texas Instruments Inc +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +-/* ccdc_davinci.c */ +- +-#include <media/ccdc_davinci.h> +-#define debug_print(x...) //printk(x) +-void ccdc_reset() +-{ +- int i; +- /* disable CCDC */ +- ccdc_enable(0); +- /* set all registers to default value */ +- for (i = 0; i <= 0x94; i += 4) { +- regw(0, i); +- } +- regw(0, PCR); +- regw(0, SYN_MODE); +- regw(0, HD_VD_WID); +- regw(0, PIX_LINES); +- regw(0, HORZ_INFO); +- regw(0, VERT_START); +- regw(0, VERT_LINES); +- regw(0xffff00ff, CULLING); +- regw(0, HSIZE_OFF); +- regw(0, SDOFST); +- regw(0, SDR_ADDR); +- regw(0, VDINT); +- regw(0, REC656IF); +- regw(0, CCDCFG); +- regw(0, FMTCFG); +- regw(0, VP_OUT); +-} +- +-void ccdc_setwin(ccdc_params_ycbcr * params) +-{ +- int horz_start, horz_nr_pixels; +- int vert_start, vert_nr_lines; +- +- /* configure horizonal and vertical starts and sizes */ +- horz_start = params->win.left << 1; +- horz_nr_pixels = (params->win.width <<1) - 1; +- regw((horz_start << 16) | horz_nr_pixels, HORZ_INFO); +- +- vert_start = params->win.top; +- +- if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { +- vert_nr_lines = (params->win.height >> 1) - 1; +- vert_start >>= 1; +- } else { +- vert_nr_lines = params->win.height - 1; +- } +- regw((vert_start << 16) | vert_start, VERT_START); +- regw(vert_nr_lines, VERT_LINES); +-} +- +-void ccdc_config_ycbcr(ccdc_params_ycbcr * params) +-{ +- u32 syn_mode; +- +- /* first reset the CCDC */ +- /* all registers have default values after reset */ +- /* This is important since we assume default values to be set in */ +- /* a lot of registers that we didn't touch */ +- ccdc_reset(); +- +- /* configure pixel format */ +- syn_mode = (params->pix_fmt & 0x3) << 12; +- +- /* configure video frame format */ +- syn_mode |= (params->frm_fmt & 0x1) << 7; +- +- /* setup BT.656 sync mode */ +- if (params->bt656_enable) { +- regw(3, REC656IF); +- +- /* configure the FID, VD, HD pin polarity */ +- /* fld,hd pol positive, vd negative, 8-bit pack mode */ +- syn_mode |= 0x00000F04; +- } else {/* y/c external sync mode */ +- syn_mode |= ((params->fid_pol & 0x1) << 4); +- syn_mode |= ((params->hd_pol & 0x1) << 3); +- syn_mode |= ((params->vd_pol & 0x1) << 2); +- } +- +- /* configure video window */ +- ccdc_setwin(params); +- +- /* configure the order of y cb cr in SD-RAM */ +- regw((params->pix_order << 11) | 0x8000, CCDCFG); +- +- /* configure the horizontal line offset */ +- /* this is done by rounding up width to a multiple of 16 pixels */ +- /* and multiply by two to account for y:cb:cr 4:2:2 data */ +- regw(((params->win.width * 2) + 31) & 0xffffffe0, HSIZE_OFF); +- +- /* configure the memory line offset */ +- if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { +- /* two fields are interleaved in memory */ +- regw(0x00000249, SDOFST); +- } +- /* enable output to SDRAM */ +- syn_mode |= (0x1 << 17); +- /* enable internal timing generator */ +- syn_mode |= (0x1 << 16); +- +- regw(syn_mode, SYN_MODE); +-} +diff --git a/drivers/media/video/davinci/ccdc_davinci.c b/drivers/media/video/davinci/ccdc_davinci.c +new file mode 100644 +index 0000000..0bb596e +--- /dev/null ++++ b/drivers/media/video/davinci/ccdc_davinci.c +@@ -0,0 +1,1007 @@ ++/* ++ * Copyright (C) 2006-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <asm/page.h> ++#include <media/davinci/ccdc_hw_device.h> ++#include "ccdc_davinci.h" ++ ++static struct device *dev; ++ ++/* Object for CCDC raw mode */ ++static struct ccdc_params_raw ccdc_hw_params_raw = { ++ .pix_fmt = CCDC_PIXFMT_RAW, ++ .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, ++ .win = CCDC_WIN_VGA, ++ .fid_pol = CCDC_PINPOL_POSITIVE, ++ .vd_pol = CCDC_PINPOL_POSITIVE, ++ .hd_pol = CCDC_PINPOL_POSITIVE, ++ .image_invert_enable = 0, ++ .data_sz = _10BITS, ++ .alaw = { ++ .b_alaw_enable = 0 ++ }, ++ .blk_clamp = { ++ .b_clamp_enable = 0, ++ .dc_sub = 0 ++ }, ++ .blk_comp = {0, 0, 0, 0}, ++ .fault_pxl = { ++ .fpc_enable = 0 ++ }, ++}; ++ ++/* Object for CCDC ycbcr mode */ ++static struct ccdc_params_ycbcr ccdc_hw_params_ycbcr = { ++ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, ++ .frm_fmt = CCDC_FRMFMT_INTERLACED, ++ .win = CCDC_WIN_PAL, ++ .fid_pol = CCDC_PINPOL_POSITIVE, ++ .vd_pol = CCDC_PINPOL_POSITIVE, ++ .hd_pol = CCDC_PINPOL_POSITIVE, ++ .bt656_enable = 1, ++ .pix_order = CCDC_PIXORDER_CBYCRY, ++ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED ++}; ++ ++#define CCDC_MAX_RAW_BAYER_FORMATS 2 ++#define CCDC_MAX_RAW_YUV_FORMATS 2 ++ ++/* Raw Bayer formats */ ++enum vpfe_hw_pix_format ccdc_raw_bayer_hw_formats[CCDC_MAX_RAW_BAYER_FORMATS] = ++ {VPFE_BAYER_8BIT_PACK_ALAW, VPFE_BAYER}; ++ ++/* Raw YUV formats */ ++enum vpfe_hw_pix_format ccdc_raw_yuv_hw_formats[CCDC_MAX_RAW_YUV_FORMATS] = ++ {VPFE_UYVY, VPFE_YUYV}; ++ ++static void *__iomem ccdc_base_addr; ++static int ccdc_addr_size; ++static void *__iomem vpss_base_addr; ++static int vpss_addr_size; ++static struct ccdc_config_params_raw ccdc_hw_params_raw_temp; ++static enum vpfe_hw_if_type ccdc_if_type; ++ ++/* register access routines */ ++static inline u32 regr(u32 offset) ++{ ++ if (offset <= ccdc_addr_size) ++ return __raw_readl(ccdc_base_addr + offset); ++ else { ++ dev_err(dev, "offset exceeds ccdc register address space\n"); ++ return -1; ++ } ++} ++ ++static inline u32 regw(u32 val, u32 offset) ++{ ++ if (offset <= ccdc_addr_size) { ++ __raw_writel(val, ccdc_base_addr + offset); ++ return val; ++ } else { ++ dev_err(dev, "offset exceeds ccdc register address space\n"); ++ return -1; ++ } ++} ++ ++/* register access routines */ ++static inline u32 regr_sb(u32 offset) ++{ ++ if (offset <= vpss_addr_size) ++ return __raw_readl(vpss_base_addr + offset); ++ else { ++ dev_err(dev, "offset exceeds vpss register address space\n"); ++ return -1; ++ } ++} ++ ++static inline u32 regw_sb(u32 val, u32 offset) ++{ ++ if (offset <= vpss_addr_size) { ++ __raw_writel(val, vpss_base_addr + offset); ++ return val; ++ } else { ++ dev_err(dev, "offset exceeds vpss register address space\n"); ++ return -1; ++ } ++} ++ ++static void ccdc_set_ccdc_base(void *addr, int size) ++{ ++ ccdc_base_addr = addr; ++ ccdc_addr_size = size; ++} ++ ++static void ccdc_set_vpss_base(void *addr, int size) ++{ ++ vpss_base_addr = addr; ++ vpss_addr_size = size; ++} ++ ++static void *ccdc_get_ccdc_base(void) ++{ ++ return (void *)ccdc_base_addr; ++} ++ ++static void *ccdc_get_vpss_base(void) ++{ ++ return (void *)vpss_base_addr; ++} ++ ++static void ccdc_enable(int flag) ++{ ++ regw(flag, PCR); ++} ++ ++static void ccdc_enable_vport(int flag) ++{ ++ if (flag) ++ /* enable video port */ ++ regw(ENABLE_VIDEO_PORT, FMTCFG); ++ else ++ regw(DISABLE_VIDEO_PORT, FMTCFG); ++} ++ ++/* ++ * ======== ccdc_setwin ======== ++ * This function will configure the window size ++ * to be capture in CCDC reg ++ */ ++void ccdc_setwin(struct ccdc_imgwin *image_win, ++ enum ccdc_frmfmt frm_fmt, ++ int ppc) ++{ ++ int horz_start, horz_nr_pixels; ++ int vert_start, vert_nr_lines; ++ int val = 0, mid_img = 0; ++ dev_dbg(dev, "\nStarting ccdc_setwin..."); ++ /* configure horizonal and vertical starts and sizes */ ++ /* Here, (ppc-1) will be different for raw and yuv modes */ ++ horz_start = image_win->left << (ppc - 1); ++ horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; ++ regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, ++ HORZ_INFO); ++ ++ vert_start = image_win->top; ++ ++ if (frm_fmt == CCDC_FRMFMT_INTERLACED) { ++ vert_nr_lines = (image_win->height >> 1) - 1; ++ vert_start >>= 1; ++ /* Since first line doesn't have any data */ ++ vert_start += 1; ++ /* configure VDINT0 */ ++ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); ++ regw(val, VDINT); ++ ++ } else { ++ /* Since first line doesn't have any data */ ++ vert_start += 1; ++ vert_nr_lines = image_win->height - 1; ++ /* configure VDINT0 and VDINT1 */ ++ /* VDINT1 will be at half of image height */ ++ mid_img = vert_start + (image_win->height / 2); ++ val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | ++ (mid_img & CCDC_VDINT_VDINT1_MASK); ++ regw(val, VDINT); ++ ++ } ++ regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, ++ VERT_START); ++ regw(vert_nr_lines, VERT_LINES); ++ dev_dbg(dev, "\nEnd of ccdc_setwin..."); ++} ++ ++static void ccdc_readregs(void) ++{ ++ unsigned int val = 0; ++ ++ val = regr(ALAW); ++ dev_notice(dev, "\nReading 0x%x to ALAW...\n", val); ++ val = regr(CLAMP); ++ dev_notice(dev, "\nReading 0x%x to CLAMP...\n", val); ++ val = regr(DCSUB); ++ dev_notice(dev, "\nReading 0x%x to DCSUB...\n", val); ++ val = regr(BLKCMP); ++ dev_notice(dev, "\nReading 0x%x to BLKCMP...\n", val); ++ val = regr(FPC_ADDR); ++ dev_notice(dev, "\nReading 0x%x to FPC_ADDR...\n", val); ++ val = regr(FPC); ++ dev_notice(dev, "\nReading 0x%x to FPC...\n", val); ++ val = regr(FMTCFG); ++ dev_notice(dev, "\nReading 0x%x to FMTCFG...\n", val); ++ val = regr(COLPTN); ++ dev_notice(dev, "\nReading 0x%x to COLPTN...\n", val); ++ val = regr(FMT_HORZ); ++ dev_notice(dev, "\nReading 0x%x to FMT_HORZ...\n", val); ++ val = regr(FMT_VERT); ++ dev_notice(dev, "\nReading 0x%x to FMT_VERT...\n", val); ++ val = regr(HSIZE_OFF); ++ dev_notice(dev, "\nReading 0x%x to HSIZE_OFF...\n", val); ++ val = regr(SDOFST); ++ dev_notice(dev, "\nReading 0x%x to SDOFST...\n", val); ++ val = regr(VP_OUT); ++ dev_notice(dev, "\nReading 0x%x to VP_OUT...\n", val); ++ val = regr(SYN_MODE); ++ dev_notice(dev, "\nReading 0x%x to SYN_MODE...\n", val); ++ val = regr(HORZ_INFO); ++ dev_notice(dev, "\nReading 0x%x to HORZ_INFO...\n", val); ++ val = regr(VERT_START); ++ dev_notice(dev, "\nReading 0x%x to VERT_START...\n", val); ++ val = regr(VERT_LINES); ++ dev_notice(dev, "\nReading 0x%x to VERT_LINES...\n", val); ++} ++ ++static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) ++{ ++ if ((ccdc_hw_params_raw.frm_fmt != CCDC_FRMFMT_INTERLACED) ++ && (ccdcparam->image_invert_enable == 1)) { ++ dev_err(dev, "\nImage invert not supported"); ++ return -1; ++ } ++ if (ccdc_hw_params_raw.alaw.b_alaw_enable) { ++ if ((ccdcparam->alaw.gama_wd > BITS_09_0) ++ || (ccdcparam->alaw.gama_wd < BITS_15_6) ++ || (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { ++ dev_err(dev, "\nInvalid data line select"); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static int ccdc_update_ycbcr_params(void *arg) ++{ ++ memcpy(&ccdc_hw_params_ycbcr, ++ (struct ccdc_params_ycbcr *)arg, ++ sizeof(struct ccdc_params_ycbcr)); ++ return 0; ++} ++ ++static int ccdc_update_raw_params(void *arg) ++{ ++ unsigned int *fpc_virtaddr = NULL; ++ unsigned int *fpc_physaddr = NULL; ++ struct ccdc_params_raw *ccd_params = &ccdc_hw_params_raw; ++ struct ccdc_config_params_raw *raw_params = ++ (struct ccdc_config_params_raw *) arg; ++ ccd_params->image_invert_enable = raw_params->image_invert_enable; ++ ++ dev_dbg(dev, "\nimage_invert_enable = %d", ++ ccd_params->image_invert_enable); ++ ++ ccd_params->data_sz = raw_params->data_sz; ++ dev_dbg(dev, "\ndata_sz = %d", ccd_params->data_sz); ++ ++ ccd_params->alaw.b_alaw_enable = raw_params->alaw.b_alaw_enable; ++ dev_dbg(dev, "\nALaw Enable = %d", ccd_params->alaw.b_alaw_enable); ++ /* copy A-Law configurations to vpfe_device, from arg ++ * passed by application */ ++ if (ccd_params->alaw.b_alaw_enable) { ++ ccd_params->alaw.gama_wd = raw_params->alaw.gama_wd; ++ dev_dbg(dev, "\nALaw Gama width = %d", ++ ccd_params->alaw.gama_wd); ++ } ++ ++ /* copy Optical Balck Clamping configurations to ++ * vpfe_device,from arg passed by application */ ++ ccd_params->blk_clamp.b_clamp_enable ++ = raw_params->blk_clamp.b_clamp_enable; ++ dev_dbg(dev, "\nb_clamp_enable = %d", ++ ccd_params->blk_clamp.b_clamp_enable); ++ if (ccd_params->blk_clamp.b_clamp_enable) { ++ /*gain */ ++ ccd_params->blk_clamp.sgain = raw_params->blk_clamp.sgain; ++ dev_dbg(dev, "\nblk_clamp.sgain = %d", ++ ccd_params->blk_clamp.sgain); ++ /*Start pixel */ ++ ccd_params->blk_clamp.start_pixel ++ = raw_params->blk_clamp.start_pixel; ++ dev_dbg(dev, "\nblk_clamp.start_pixel = %d", ++ ccd_params->blk_clamp.start_pixel); ++ /*No of line to be avg */ ++ ccd_params->blk_clamp.sample_ln ++ = raw_params->blk_clamp.sample_ln; ++ dev_dbg(dev, "\nblk_clamp.sample_ln = %d", ++ ccd_params->blk_clamp.sample_ln); ++ /*No of pixel/line to be avg */ ++ ccd_params->blk_clamp.sample_pixel ++ = raw_params->blk_clamp.sample_pixel; ++ dev_dbg(dev, "\nblk_clamp.sample_pixel = %d", ++ ccd_params->blk_clamp.sample_pixel); ++ } else { /* configure DCSub */ ++ ++ ccd_params->blk_clamp.dc_sub = raw_params->blk_clamp.dc_sub; ++ dev_dbg(dev, "\nblk_clamp.dc_sub = %d", ++ ccd_params->blk_clamp.dc_sub); ++ } ++ ++ /* copy BalckLevel Compansation configurations to ++ * vpfe_device,from arg passed by application ++ */ ++ ccd_params->blk_comp.r_comp = raw_params->blk_comp.r_comp; ++ ccd_params->blk_comp.gr_comp = raw_params->blk_comp.gr_comp; ++ ccd_params->blk_comp.b_comp = raw_params->blk_comp.b_comp; ++ ccd_params->blk_comp.gb_comp = raw_params->blk_comp.gb_comp; ++ dev_dbg(dev, "\nblk_comp.r_comp = %d", ++ ccd_params->blk_comp.r_comp); ++ dev_dbg(dev, "\nblk_comp.gr_comp = %d", ++ ccd_params->blk_comp.gr_comp); ++ dev_dbg(dev, "\nblk_comp.b_comp = %d", ++ ccd_params->blk_comp.b_comp); ++ dev_dbg(dev, "\nblk_comp.gb_comp = %d", ++ ccd_params->blk_comp.gb_comp); ++ ++ /* copy FPC configurations to vpfe_device,from ++ * arg passed by application ++ */ ++ ccd_params->fault_pxl.fpc_enable = raw_params->fault_pxl.fpc_enable; ++ dev_dbg(dev, "\nfault_pxl.fpc_enable = %d", ++ ccd_params->fault_pxl.fpc_enable); ++ ++ if (ccd_params->fault_pxl.fpc_enable) { ++ fpc_physaddr = ++ (unsigned int *)ccd_params->fault_pxl.fpc_table_addr; ++ ++ fpc_virtaddr = (unsigned int *) ++ phys_to_virt((unsigned long) ++ fpc_physaddr); ++ ++ /* Allocate memory for FPC table if current ++ * FPC table buffer is not big enough to ++ * accomodate FPC Number requested ++ */ ++ if (raw_params->fault_pxl.fp_num != ++ ccd_params->fault_pxl.fp_num) { ++ if (fpc_physaddr != NULL) { ++ free_pages((unsigned long) ++ fpc_physaddr, ++ get_order ++ (ccd_params-> ++ fault_pxl.fp_num * FP_NUM_BYTES)); ++ ++ } ++ ++ /* Allocate memory for FPC table */ ++ fpc_virtaddr = (unsigned int *) ++ __get_free_pages(GFP_KERNEL | ++ GFP_DMA, ++ get_order ++ (raw_params-> ++ fault_pxl.fp_num * FP_NUM_BYTES)); ++ ++ if (fpc_virtaddr == NULL) { ++ dev_err(dev, ++ "\nUnable to allocate memory for FPC"); ++ return -1; ++ } ++ fpc_physaddr = ++ (unsigned int *)virt_to_phys((void *)fpc_virtaddr); ++ } ++ ++ /* Copy number of fault pixels and FPC table */ ++ ccd_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; ++ if (copy_from_user((void *)fpc_virtaddr, ++ (void *)raw_params-> ++ fault_pxl.fpc_table_addr, ++ (unsigned long)ccd_params-> ++ fault_pxl.fp_num * FP_NUM_BYTES)) { ++ dev_err(dev, "\n copy_from_user failed"); ++ return -1; ++ } ++ ++ ccd_params->fault_pxl.fpc_table_addr = ++ (unsigned int)fpc_physaddr; ++ } ++ return 0; ++} ++ ++static int ccdc_close(struct device *dev) ++{ ++ unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; ++ fpc_physaddr = (unsigned int *) ++ ccdc_hw_params_raw.fault_pxl.fpc_table_addr; ++ ++ if (fpc_physaddr != NULL) { ++ fpc_virtaddr = (unsigned int *) ++ phys_to_virt((unsigned long)fpc_physaddr); ++ free_pages((unsigned long)fpc_virtaddr, ++ get_order(ccdc_hw_params_raw.fault_pxl. ++ fp_num * FP_NUM_BYTES)); ++ } ++ return 0; ++} ++ ++/* ++ * ======== ccdc_reset ======== ++ * ++ * This function will reset all CCDc reg ++ */ ++static void ccdc_reset(void) ++{ ++ int i; ++ ++ /* disable CCDC */ ++ ccdc_enable(0); ++ /* set all registers to default value */ ++ for (i = 0; i <= 0x94; i += 4) ++ regw(0, i); ++ regw(0, PCR); ++ regw(0, SYN_MODE); ++ regw(0, HD_VD_WID); ++ regw(0, PIX_LINES); ++ regw(0, HORZ_INFO); ++ regw(0, VERT_START); ++ regw(0, VERT_LINES); ++ regw(0xffff00ff, CULLING); ++ regw(0, HSIZE_OFF); ++ regw(0, SDOFST); ++ regw(0, SDR_ADDR); ++ regw(0, VDINT); ++ regw(0, REC656IF); ++ regw(0, CCDCFG); ++ regw(0, FMTCFG); ++ regw(0, VP_OUT); ++} ++ ++static int ccdc_open(struct device *device) ++{ ++ dev = device; ++ ccdc_reset(); ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ ccdc_enable_vport(1); ++ return 0; ++} ++ ++static u32 ccdc_sbl_reset(void) ++{ ++ u32 sb_reset; ++ sb_reset = regr_sb(SBL_PCR_VPSS); ++ regw_sb((sb_reset & SBL_PCR_CCDC_WBL_O), SBL_PCR_VPSS); ++ return sb_reset; ++} ++ ++/* Parameter operations */ ++static int ccdc_setparams(void *params) ++{ ++ int x; ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ x = copy_from_user(&ccdc_hw_params_raw_temp, ++ (struct ccdc_config_params_raw *)params, ++ sizeof(struct ccdc_config_params_raw)); ++ if (x) { ++ dev_err(dev, "ccdc_setparams: error in copying" ++ "ccdc params, %d\n", x); ++ return -1; ++ } ++ ++ if (!validate_ccdc_param(&ccdc_hw_params_raw_temp)) { ++ if (!ccdc_update_raw_params(&ccdc_hw_params_raw_temp)) ++ return 0; ++ } ++ } else ++ return ccdc_update_ycbcr_params(params); ++ return -1; ++} ++ ++/* ++ * ======== ccdc_config_ycbcr ======== ++ * This function will configure CCDC for YCbCr parameters ++ */ ++void ccdc_config_ycbcr(void) ++{ ++ u32 syn_mode; ++ unsigned int val; ++ struct ccdc_params_ycbcr *params = &ccdc_hw_params_ycbcr; ++ ++ /* first reset the CCDC */ ++ /* all registers have default values after reset */ ++ /* This is important since we assume default values to be set in */ ++ /* a lot of registers that we didn't touch */ ++ dev_dbg(dev, "\nStarting ccdc_config_ycbcr..."); ++ ccdc_reset(); ++ ++ /* configure pixel format */ ++ syn_mode = (params->pix_fmt & 0x3) << 12; ++ ++ /* configure video frame format */ ++ syn_mode |= (params->frm_fmt & 0x1) << 7; ++ ++ /* setup BT.656 sync mode */ ++ if (params->bt656_enable) { ++ regw(3, REC656IF); ++ ++ /* configure the FID, VD, HD pin polarity */ ++ /* fld,hd pol positive, vd negative, 8-bit pack mode */ ++ syn_mode |= 0x00000F04; ++ } else { ++ /* y/c external sync mode */ ++ syn_mode |= ((params->fid_pol & 0x1) << 4); ++ syn_mode |= ((params->hd_pol & 0x1) << 3); ++ syn_mode |= ((params->vd_pol & 0x1) << 2); ++ } ++ ++ /* configure video window */ ++ ccdc_setwin(¶ms->win, params->frm_fmt, 2); ++ ++ /* configure the order of y cb cr in SD-RAM */ ++ regw((params->pix_order << 11) | 0x8000, CCDCFG); ++ ++ /* configure the horizontal line offset */ ++ /* this is done by rounding up width to a multiple of 16 pixels */ ++ /* and multiply by two to account for y:cb:cr 4:2:2 data */ ++ regw(((params->win.width * 2) + 31) & 0xffffffe0, HSIZE_OFF); ++ ++ /* configure the memory line offset */ ++ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) ++ /* two fields are interleaved in memory */ ++ regw(0x00000249, SDOFST); ++ /* enable output to SDRAM */ ++ syn_mode |= (0x1 << 17); ++ /* enable internal timing generator */ ++ syn_mode |= (0x1 << 16); ++ ++ syn_mode |= CCDC_DATA_PACK_ENABLE; ++ regw(syn_mode, SYN_MODE); ++ ++ val = (unsigned int)ccdc_sbl_reset(); ++ dev_dbg(dev, "\nReading 0x%x from SBL...\n", val); ++ dev_dbg(dev, "\nEnd of ccdc_config_ycbcr...\n"); ++ ccdc_readregs(); ++} ++ ++/* ++ * ======== ccdc_config_raw ======== ++ * ++ * This function will configure CCDC for Raw mode parameters ++ */ ++void ccdc_config_raw(void) ++{ ++ struct ccdc_params_raw *params = &ccdc_hw_params_raw; ++ unsigned int syn_mode = 0; ++ unsigned int val; ++ dev_dbg(dev, "\nStarting ccdc_config_raw..."); ++ /* Reset CCDC */ ++ ccdc_reset(); ++ /* Disable latching function registers on VSYNC */ ++ regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); ++ ++ /* Configure the vertical sync polarity(SYN_MODE.VDPOL) */ ++ syn_mode = (params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT; ++ ++ /* Configure the horizontal sync polarity (SYN_MODE.HDPOL) */ ++ syn_mode |= (params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT; ++ ++ /* Configure frame id polarity (SYN_MODE.FLDPOL) */ ++ syn_mode |= (params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT; ++ ++ /* Configure frame format(progressive or interlace) */ ++ syn_mode |= (params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT; ++ ++ /* Configure the data size(SYNMODE.DATSIZ) */ ++ syn_mode |= (params->data_sz & CCDC_DATA_SZ_MASK) << CCDC_DATA_SZ_SHIFT; ++ ++ /* Configure pixel format (Input mode) */ ++ syn_mode |= (params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT; ++ ++ /* Configure VP2SDR bit of syn_mode = 0 */ ++ syn_mode &= CCDC_VP2SDR_DISABLE; ++ ++ /* Enable write enable bit */ ++ syn_mode |= CCDC_WEN_ENABLE; ++ ++ /* Disable output to resizer */ ++ syn_mode &= CCDC_SDR2RSZ_DISABLE; ++ ++ /* enable internal timing generator */ ++ syn_mode |= CCDC_VDHDEN_ENABLE; ++ ++ /* Enable and configure aLaw register if needed */ ++ if (params->alaw.b_alaw_enable) { ++ val = (params->alaw.gama_wd & CCDC_ALAW_GAMA_WD_MASK); ++ /*set enable bit of alaw */ ++ val |= CCDC_ALAW_ENABLE; ++ regw(val, ALAW); ++ ++ dev_dbg(dev, "\nWriting 0x%x to ALAW...\n", val); ++ } ++ ++ /* configure video window */ ++ ccdc_setwin(¶ms->win, params->frm_fmt, PPC_RAW); ++ ++ if (params->blk_clamp.b_clamp_enable) { ++ /*gain */ ++ val = (params->blk_clamp.sgain) & CCDC_BLK_SGAIN_MASK; ++ /*Start pixel */ ++ val |= (params->blk_clamp.start_pixel & CCDC_BLK_ST_PXL_MASK) ++ << CCDC_BLK_ST_PXL_SHIFT; ++ /*No of line to be avg */ ++ val |= (params->blk_clamp.sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) ++ << CCDC_BLK_SAMPLE_LINE_SHIFT; ++ /*No of pixel/line to be avg */ ++ val |= ++ (params->blk_clamp.sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) ++ << CCDC_BLK_SAMPLE_LN_SHIFT; ++ /*Enable the Black clamping */ ++ val |= CCDC_BLK_CLAMP_ENABLE; ++ regw(val, CLAMP); ++ ++ dev_dbg(dev, "\nWriting 0x%x to CLAMP...\n", val); ++ /*If Black clamping is enable then make dcsub 0 */ ++ regw(DCSUB_DEFAULT_VAL, DCSUB); ++ dev_dbg(dev, "\nWriting 0x00000000 to DCSUB...\n"); ++ ++ } else { ++ /* configure DCSub */ ++ val = (params->blk_clamp.dc_sub) & CCDC_BLK_DC_SUB_MASK; ++ regw(val, DCSUB); ++ ++ dev_dbg(dev, "\nWriting 0x%x to DCSUB...\n", val); ++ regw(CLAMP_DEFAULT_VAL, CLAMP); ++ ++ dev_dbg(dev, "\nWriting 0x0000 to CLAMP...\n"); ++ } ++ ++ /* Configure Black level compensation */ ++ val = (params->blk_comp.b_comp & CCDC_BLK_COMP_MASK); ++ val |= (params->blk_comp.gb_comp & CCDC_BLK_COMP_MASK) ++ << CCDC_BLK_COMP_GB_COMP_SHIFT; ++ val |= (params->blk_comp.gr_comp & CCDC_BLK_COMP_MASK) ++ << CCDC_BLK_COMP_GR_COMP_SHIFT; ++ val |= (params->blk_comp.r_comp & CCDC_BLK_COMP_MASK) ++ << CCDC_BLK_COMP_R_COMP_SHIFT; ++ ++ regw(val, BLKCMP); ++ ++ dev_dbg(dev, "\nWriting 0x%x to BLKCMP...\n", val); ++ dev_dbg(dev, "\nbelow regw(val, BLKCMP)..."); ++ /* Initially disable FPC */ ++ val = CCDC_FPC_DISABLE; ++ regw(val, FPC); ++ /* Configure Fault pixel if needed */ ++ if (params->fault_pxl.fpc_enable) { ++ regw(params->fault_pxl.fpc_table_addr, FPC_ADDR); ++ ++ dev_dbg(dev, "\nWriting 0x%x to FPC_ADDR...\n", ++ (params->fault_pxl.fpc_table_addr)); ++ /* Write the FPC params with FPC disable */ ++ val = params->fault_pxl.fp_num & CCDC_FPC_FPC_NUM_MASK; ++ regw(val, FPC); ++ ++ dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val); ++ /* read the FPC register */ ++ val = regr(FPC); ++ val |= CCDC_FPC_ENABLE; ++ regw(val, FPC); ++ ++ dev_dbg(dev, "\nWriting 0x%x to FPC...\n", val); ++ } ++ /* If data size is 8 bit then pack the data */ ++ if ((params->data_sz == _8BITS) || params->alaw.b_alaw_enable) ++ syn_mode |= CCDC_DATA_PACK_ENABLE; ++#if VIDEO_PORT_ENABLE ++ /* enable video port */ ++ val = ENABLE_VIDEO_PORT; ++#else ++ /* disable video port */ ++ val = DISABLE_VIDEO_PORT; ++#endif ++ ++ if (params->data_sz == _8BITS) ++ val |= (_10BITS & CCDC_FMTCFG_VPIN_MASK) ++ << CCDC_FMTCFG_VPIN_SHIFT; ++ else ++ val |= (params->data_sz & CCDC_FMTCFG_VPIN_MASK) ++ << CCDC_FMTCFG_VPIN_SHIFT; ++ ++ /* Write value in FMTCFG */ ++ regw(val, FMTCFG); ++ ++ dev_dbg(dev, "\nWriting 0x%x to FMTCFG...\n", val); ++ ++ /* Configure the color pattern according to mt9t001 sensor */ ++ regw(CCDC_COLPTN_VAL, COLPTN); ++ ++ dev_dbg(dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); ++ /* Configure Data formatter(Video port) pixel selection ++ * (FMT_HORZ, FMT_VERT) ++ */ ++ val = 0; ++ val |= ((params->win.left) & CCDC_FMT_HORZ_FMTSPH_MASK) ++ << CCDC_FMT_HORZ_FMTSPH_SHIFT; ++ val |= (((params->win.width)) & CCDC_FMT_HORZ_FMTLNH_MASK); ++ regw(val, FMT_HORZ); ++ ++ dev_dbg(dev, "\nWriting 0x%x to FMT_HORZ...\n", val); ++ val = 0; ++ val |= (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) ++ << CCDC_FMT_VERT_FMTSLV_SHIFT; ++ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) ++ val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; ++ else ++ val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; ++ ++ dev_dbg(dev, "\nparams->win.height 0x%x ...\n", ++ params->win.height); ++ regw(val, FMT_VERT); ++ ++ dev_dbg(dev, "\nWriting 0x%x to FMT_VERT...\n", val); ++ ++ dev_dbg(dev, "\nbelow regw(val, FMT_VERT)..."); ++ ++ /* Configure Horizontal offset register */ ++ /* If pack 8 is enabled then 1 pixel will take 1 byte */ ++ if ((params->data_sz == _8BITS) || params->alaw.b_alaw_enable) ++ regw(((params->win.width) + CCDC_32BYTE_ALIGN_VAL) ++ & CCDC_HSIZE_OFF_MASK, HSIZE_OFF); ++ ++ else ++ /* else one pixel will take 2 byte */ ++ regw(((params->win.width * TWO_BYTES_PER_PIXEL) ++ + CCDC_32BYTE_ALIGN_VAL) ++ & CCDC_HSIZE_OFF_MASK, HSIZE_OFF); ++ ++ /* Set value for SDOFST */ ++ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { ++ if (params->image_invert_enable) { ++ /* For intelace inverse mode */ ++ regw(INTERLACED_IMAGE_INVERT, SDOFST); ++ dev_dbg(dev, "\nWriting 0x4B6D to SDOFST...\n"); ++ } ++ ++ else { ++ /* For intelace non inverse mode */ ++ regw(INTERLACED_NO_IMAGE_INVERT, SDOFST); ++ dev_dbg(dev, "\nWriting 0x0249 to SDOFST...\n"); ++ } ++ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { ++ regw(PROGRESSIVE_NO_IMAGE_INVERT, SDOFST); ++ dev_dbg(dev, "\nWriting 0x0000 to SDOFST...\n"); ++ } ++ ++ /* Configure video port pixel selection (VPOUT) */ ++ /* Here -1 is to make the height value less than FMT_VERT.FMTLNV */ ++ if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) ++ val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) ++ << CCDC_VP_OUT_VERT_NUM_SHIFT; ++ else ++ val = ++ ((((params->win. ++ height >> CCDC_INTERLACED_HEIGHT_SHIFT) - ++ 1) & CCDC_VP_OUT_VERT_NUM_MASK)) ++ << CCDC_VP_OUT_VERT_NUM_SHIFT; ++ ++ val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) ++ << CCDC_VP_OUT_HORZ_NUM_SHIFT; ++ val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; ++ regw(val, VP_OUT); ++ ++ dev_dbg(dev, "\nWriting 0x%x to VP_OUT...\n", val); ++ regw(syn_mode, SYN_MODE); ++ dev_dbg(dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); ++ ++ val = (unsigned int)ccdc_sbl_reset(); ++ dev_dbg(dev, "\nReading 0x%x from SBL...\n", val); ++ ++ dev_dbg(dev, "\nend of ccdc_config_raw..."); ++ ccdc_readregs(); ++} ++ ++static int ccdc_configure(void) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ dev_info(dev, "calling ccdc_config_raw()\n"); ++ ccdc_config_raw(); ++ } else { ++ dev_info(dev, "calling ccdc_config_ycbcr()\n"); ++ ccdc_config_ycbcr(); ++ } ++ return 0; ++} ++ ++static int ccdc_set_buftype(enum ccdc_buftype buf_type) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ ccdc_hw_params_raw.buf_type = buf_type; ++ else ++ ccdc_hw_params_ycbcr.buf_type = buf_type; ++ return 0; ++} ++ ++static int ccdc_get_buftype(enum ccdc_buftype *buf_type) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ *buf_type = ccdc_hw_params_raw.buf_type; ++ else ++ *buf_type = ccdc_hw_params_ycbcr.buf_type; ++ return 0; ++} ++ ++static int ccdc_enum_pix(enum vpfe_hw_pix_format *hw_pix, int i) ++{ ++ int ret = -EINVAL; ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ if (i < CCDC_MAX_RAW_BAYER_FORMATS) { ++ *hw_pix = ccdc_raw_bayer_hw_formats[i]; ++ ret = 0; ++ } ++ } else { ++ if (i < CCDC_MAX_RAW_YUV_FORMATS) { ++ *hw_pix = ccdc_raw_yuv_hw_formats[i]; ++ ret = 0; ++ } ++ } ++ return ret; ++} ++ ++static int ccdc_set_pixel_format(enum vpfe_hw_pix_format pixfmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ ccdc_hw_params_raw.pix_fmt = CCDC_PIXFMT_RAW; ++ if (pixfmt == VPFE_BAYER_8BIT_PACK_ALAW) ++ ccdc_hw_params_raw.alaw.b_alaw_enable = 1; ++ else if (pixfmt != VPFE_BAYER) ++ return -1; ++ } else { ++ if (pixfmt == VPFE_YUYV) ++ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; ++ else if (pixfmt == VPFE_UYVY) ++ ccdc_hw_params_ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; ++ else ++ return -1; ++ } ++ return 0; ++} ++ ++static int ccdc_get_pixel_format(enum vpfe_hw_pix_format *pixfmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ if (ccdc_hw_params_raw.alaw.b_alaw_enable) ++ *pixfmt = VPFE_BAYER_8BIT_PACK_ALAW; ++ else ++ *pixfmt = VPFE_BAYER; ++ else { ++ if (ccdc_hw_params_ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) ++ *pixfmt = VPFE_YUYV; ++ else ++ *pixfmt = VPFE_UYVY; ++ } ++ return 0; ++} ++ ++static int ccdc_set_image_window(struct v4l2_rect *win) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ ccdc_hw_params_raw.win.top = win->top; ++ ccdc_hw_params_raw.win.left = win->left; ++ ccdc_hw_params_raw.win.width = win->width; ++ ccdc_hw_params_raw.win.height = win->height; ++ } else { ++ ccdc_hw_params_ycbcr.win.top = win->top; ++ ccdc_hw_params_ycbcr.win.left = win->left; ++ ccdc_hw_params_ycbcr.win.width = win->width; ++ ccdc_hw_params_ycbcr.win.height = win->height; ++ } ++ return 0; ++} ++ ++static int ccdc_get_image_window(struct v4l2_rect *win) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ win->top = ccdc_hw_params_raw.win.top; ++ win->left = ccdc_hw_params_raw.win.left; ++ win->width = ccdc_hw_params_raw.win.width; ++ win->height = ccdc_hw_params_raw.win.height; ++ } else { ++ win->top = ccdc_hw_params_ycbcr.win.top; ++ win->left = ccdc_hw_params_ycbcr.win.left; ++ win->width = ccdc_hw_params_ycbcr.win.width; ++ win->height = ccdc_hw_params_ycbcr.win.height; ++ } ++ return 0; ++} ++ ++static int ccdc_get_line_length(unsigned int *len) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) { ++ if ((ccdc_hw_params_raw.alaw.b_alaw_enable) || ++ (ccdc_hw_params_raw.data_sz == _8BITS)) ++ *len = ccdc_hw_params_raw.win.width; ++ else ++ *len = ccdc_hw_params_raw.win.width * 2; ++ } else ++ *len = ccdc_hw_params_ycbcr.win.width * 2; ++ return 0; ++} ++ ++static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ ccdc_hw_params_raw.frm_fmt = frm_fmt; ++ else ++ ccdc_hw_params_ycbcr.frm_fmt = frm_fmt; ++ return 0; ++} ++ ++static int ccdc_get_frame_format(enum ccdc_frmfmt *frm_fmt) ++{ ++ if (ccdc_if_type == VPFE_RAW_BAYER) ++ *frm_fmt = ccdc_hw_params_raw.frm_fmt; ++ else ++ *frm_fmt = ccdc_hw_params_ycbcr.frm_fmt; ++ return 0; ++} ++ ++static int ccdc_getfid(void) ++{ ++ int fid = (regr(SYN_MODE) >> 15) & 0x1; ++ return fid; ++} ++ ++/* misc operations */ ++static inline void ccdc_setfbaddr(unsigned long addr) ++{ ++ regw(addr & 0xffffffe0, SDR_ADDR); ++} ++ ++static int ccdc_set_hw_if_type(enum vpfe_hw_if_type iface) ++{ ++ ccdc_if_type = iface; ++ return 0; ++} ++ ++struct ccdc_hw_device ccdc_hw_dev = { ++ .name = "DM6446 CCDC", ++ .set_ccdc_base = ccdc_set_ccdc_base, ++ .set_vpss_base = ccdc_set_vpss_base, ++ .get_ccdc_base = ccdc_get_ccdc_base, ++ .get_vpss_base = ccdc_get_vpss_base, ++ .open = ccdc_open, ++ .reset = ccdc_sbl_reset, ++ .enable = ccdc_enable, ++ .set_hw_if_type = ccdc_set_hw_if_type, ++ .setparams = ccdc_setparams, ++ .configure = ccdc_configure, ++ .set_buftype = ccdc_set_buftype, ++ .get_buftype = ccdc_get_buftype, ++ .enum_pix = ccdc_enum_pix, ++ .set_pixelformat = ccdc_set_pixel_format, ++ .get_pixelformat = ccdc_get_pixel_format, ++ .set_frame_format = ccdc_set_frame_format, ++ .get_frame_format = ccdc_get_frame_format, ++ .set_image_window = ccdc_set_image_window, ++ .get_image_window = ccdc_get_image_window, ++ .get_line_length = ccdc_get_line_length, ++ .setfbaddr = ccdc_setfbaddr, ++ .getfid = ccdc_getfid, ++ .close = ccdc_close ++}; ++EXPORT_SYMBOL(ccdc_hw_dev); ++ ++static int davinci_ccdc_init(void) ++{ ++ return 0; ++} ++ ++static void davinci_ccdc_exit(void) ++{ ++} ++ ++subsys_initcall(davinci_ccdc_init); ++module_exit(davinci_ccdc_exit); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/video/davinci/ccdc_davinci.h b/drivers/media/video/davinci/ccdc_davinci.h +new file mode 100644 +index 0000000..188e4f1 +--- /dev/null ++++ b/drivers/media/video/davinci/ccdc_davinci.h +@@ -0,0 +1,335 @@ ++/* ++ * Copyright (C) 2006-2009 Texas Instruments Inc ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef _CCDC_DAVINCI_H ++#define _CCDC_DAVINCI_H ++#include <media/davinci/ccdc_common.h> ++ ++/* enum for No of pixel per line to be avg. in Black Clamping*/ ++enum sample_length { ++ _1PIXELS = 0, ++ _2PIXELS, ++ _4PIXELS, ++ _8PIXELS, ++ _16PIXELS ++}; ++ ++/* Define to enable/disable video port */ ++#define VIDEO_PORT_ENABLE (1) ++#define FP_NUM_BYTES (4) ++/* Define for extra pixel/line and extra lines/frame */ ++#define NUM_EXTRAPIXELS 8 ++#define NUM_EXTRALINES 8 ++ ++/* settings for commonly used video formats */ ++#define CCDC_WIN_PAL {0, 0, 720, 576} ++/* ntsc square pixel */ ++#define CCDC_WIN_VGA {0, 0, (640 + NUM_EXTRAPIXELS), (480 + NUM_EXTRALINES)} ++ ++/* enum for No of lines in Black Clamping */ ++enum sample_line { ++ _1LINES = 0, ++ _2LINES, ++ _4LINES, ++ _8LINES, ++ _16LINES ++}; ++ ++/* enum for Alaw gama width */ ++enum gama_width { ++ BITS_15_6 = 0, ++ BITS_14_5, ++ BITS_13_4, ++ BITS_12_3, ++ BITS_11_2, ++ BITS_10_1, ++ BITS_09_0 ++}; ++ ++enum data_size { ++ _16BITS = 0, ++ _15BITS, ++ _14BITS, ++ _13BITS, ++ _12BITS, ++ _11BITS, ++ _10BITS, ++ _8BITS ++}; ++ ++struct ccdc_imgwin { ++ unsigned int top; ++ unsigned int left; ++ unsigned int width; ++ unsigned int height; ++}; ++ ++/* structure for ALaw */ ++struct a_law { ++ /* Enable/disable A-Law */ ++ unsigned char b_alaw_enable; ++ /*Gama Width Input */ ++ enum gama_width gama_wd; ++}; ++ ++/* structure for Black Clamping */ ++struct black_clamp { ++ unsigned char b_clamp_enable; ++ /* only if bClampEnable is TRUE */ ++ enum sample_length sample_pixel; ++ /* only if bClampEnable is TRUE */ ++ enum sample_line sample_ln; ++ /* only if bClampEnable is TRUE */ ++ unsigned short start_pixel; ++ /* only if bClampEnable is TRUE */ ++ unsigned short sgain; ++ /* only if bClampEnable is FALSE */ ++ unsigned short dc_sub; ++}; ++ ++/* structure for Black Level Compensation */ ++struct black_compensation { ++ /* Constant value to subtract from Red component */ ++ char r_comp; ++ /* Constant value to subtract from Gr component */ ++ char gr_comp; ++ /* Constant value to subtract from Blue component */ ++ char b_comp; ++ /* Constant value to subtract from Gb component */ ++ char gb_comp; ++}; ++ ++/* structure for fault pixel correction */ ++struct fault_pixel { ++ /*Enable or Disable fault pixel correction */ ++ unsigned char fpc_enable; ++ /*Number of fault pixel */ ++ unsigned short fp_num; ++ /*Address of fault pixel table */ ++ unsigned int fpc_table_addr; ++}; ++ ++/* Structure for CCDC configuration parameters for raw capture mode passed ++ * by application ++ */ ++struct ccdc_config_params_raw { ++ /* pixel format */ ++ enum ccdc_pixfmt pix_fmt; ++ /* progressive or interlaced frame */ ++ enum ccdc_frmfmt frm_fmt; ++ /* video window */ ++ struct ccdc_imgwin win; ++ /* field id polarity */ ++ enum ccdc_pinpol fid_pol; ++ /* vertical sync polarity */ ++ enum ccdc_pinpol vd_pol; ++ /* horizontal sync polarity */ ++ enum ccdc_pinpol hd_pol; ++ /* enable to store the image in inverse order in ++ * memory(bottom to top) ++ */ ++ unsigned char image_invert_enable; ++ /* data size value from 8 to 16 bits */ ++ enum data_size data_sz; ++ /* Structure for Optional A-Law */ ++ struct a_law alaw; ++ /* Structure for Optical Black Clamp */ ++ struct black_clamp blk_clamp; ++ /* Structure for Black Compensation */ ++ struct black_compensation blk_comp; ++ /* Structure for Fault Pixel Module Configuration */ ++ struct fault_pixel fault_pxl; ++}; ++ ++struct ccdc_params_ycbcr { ++ /* pixel format */ ++ enum ccdc_pixfmt pix_fmt; ++ /* progressive or interlaced frame */ ++ enum ccdc_frmfmt frm_fmt; ++ /* video window */ ++ struct ccdc_imgwin win; ++ /* field id polarity */ ++ enum ccdc_pinpol fid_pol; ++ /* vertical sync polarity */ ++ enum ccdc_pinpol vd_pol; ++ /* horizontal sync polarity */ ++ enum ccdc_pinpol hd_pol; ++ /* enable BT.656 embedded sync mode */ ++ int bt656_enable; ++ /* cb:y:cr:y or y:cb:y:cr in memory */ ++ enum ccdc_pixorder pix_order; ++ /* interleaved or separated fields */ ++ enum ccdc_buftype buf_type; ++}; ++ ++#ifdef __KERNEL__ ++#include <linux/io.h> ++/* Structure for CCDC configuration parameters for raw capture mode */ ++struct ccdc_params_raw { ++ /* pixel format */ ++ enum ccdc_pixfmt pix_fmt; ++ /* progressive or interlaced frame */ ++ enum ccdc_frmfmt frm_fmt; ++ /* video window */ ++ struct ccdc_imgwin win; ++ /* field id polarity */ ++ enum ccdc_pinpol fid_pol; ++ /* vertical sync polarity */ ++ enum ccdc_pinpol vd_pol; ++ /* horizontal sync polarity */ ++ enum ccdc_pinpol hd_pol; ++ /* interleaved or separated fields */ ++ enum ccdc_buftype buf_type; ++ /* enable to store the image in inverse ++ * order in memory(bottom to top) ++ */ ++ unsigned char image_invert_enable; ++ /* data size value from 8 to 16 bits */ ++ enum data_size data_sz; ++ /* Structure for Optional A-Law */ ++ struct a_law alaw; ++ /* Structure for Optical Black Clamp */ ++ struct black_clamp blk_clamp; ++ /* Structure for Black Compensation */ ++ struct black_compensation blk_comp; ++ /* Structure for Fault Pixel Module Configuration */ ++ struct fault_pixel fault_pxl; ++}; ++ ++/**************************************************************************\ ++* Register OFFSET Definitions ++\**************************************************************************/ ++ ++#define PID 0x0 ++#define PCR 0x4 ++#define SYN_MODE 0x8 ++#define HD_VD_WID 0xc ++#define PIX_LINES 0x10 ++#define HORZ_INFO 0x14 ++#define VERT_START 0x18 ++#define VERT_LINES 0x1c ++#define CULLING 0x20 ++#define HSIZE_OFF 0x24 ++#define SDOFST 0x28 ++#define SDR_ADDR 0x2c ++#define CLAMP 0x30 ++#define DCSUB 0x34 ++#define COLPTN 0x38 ++#define BLKCMP 0x3c ++#define FPC 0x40 ++#define FPC_ADDR 0x44 ++#define VDINT 0x48 ++#define ALAW 0x4c ++#define REC656IF 0x50 ++#define CCDCFG 0x54 ++#define FMTCFG 0x58 ++#define FMT_HORZ 0x5c ++#define FMT_VERT 0x60 ++#define FMT_ADDR0 0x64 ++#define FMT_ADDR1 0x68 ++#define FMT_ADDR2 0x6c ++#define FMT_ADDR3 0x70 ++#define FMT_ADDR4 0x74 ++#define FMT_ADDR5 0x78 ++#define FMT_ADDR6 0x7c ++#define FMT_ADDR7 0x80 ++#define PRGEVEN_0 0x84 ++#define PRGEVEN_1 0x88 ++#define PRGODD_0 0x8c ++#define PRGODD_1 0x90 ++#define VP_OUT 0x94 ++ ++ ++/*************************************************************** ++* Define for various register bit mask and shifts for CCDC ++****************************************************************/ ++#define CCDC_FID_POL_MASK (0x01) ++#define CCDC_FID_POL_SHIFT (4) ++#define CCDC_HD_POL_MASK (0x01) ++#define CCDC_HD_POL_SHIFT (3) ++#define CCDC_VD_POL_MASK (0x01) ++#define CCDC_VD_POL_SHIFT (2) ++#define CCDC_HSIZE_OFF_MASK (0xffffffe0) ++#define CCDC_32BYTE_ALIGN_VAL (31) ++#define CCDC_FRM_FMT_MASK (0x01) ++#define CCDC_FRM_FMT_SHIFT (7) ++#define CCDC_DATA_SZ_MASK (0x07) ++#define CCDC_DATA_SZ_SHIFT (8) ++#define CCDC_PIX_FMT_MASK (0x03) ++#define CCDC_PIX_FMT_SHIFT (12) ++#define CCDC_VP2SDR_DISABLE (0xFFFBFFFF) ++#define CCDC_WEN_ENABLE (0x01 << 17) ++#define CCDC_SDR2RSZ_DISABLE (0xFFF7FFFF) ++#define CCDC_VDHDEN_ENABLE (0x01 << 16) ++#define CCDC_LPF_ENABLE (0x01 << 14) ++#define CCDC_ALAW_ENABLE (0x01 << 3) ++#define CCDC_ALAW_GAMA_WD_MASK (0x07) ++#define CCDC_BLK_CLAMP_ENABLE (0x01 << 31) ++#define CCDC_BLK_SGAIN_MASK (0x1F) ++#define CCDC_BLK_ST_PXL_MASK (0x7FFF) ++#define CCDC_BLK_ST_PXL_SHIFT (10) ++#define CCDC_BLK_SAMPLE_LN_MASK (0x07) ++#define CCDC_BLK_SAMPLE_LN_SHIFT (28) ++#define CCDC_BLK_SAMPLE_LINE_MASK (0x07) ++#define CCDC_BLK_SAMPLE_LINE_SHIFT (25) ++#define CCDC_BLK_DC_SUB_MASK (0x03FFF) ++#define CCDC_BLK_COMP_MASK (0x000000FF) ++#define CCDC_BLK_COMP_GB_COMP_SHIFT (8) ++#define CCDC_BLK_COMP_GR_COMP_SHIFT (16) ++#define CCDC_BLK_COMP_R_COMP_SHIFT (24) ++#define CCDC_LATCH_ON_VSYNC_DISABLE (0x01 << 15) ++#define CCDC_FPC_ENABLE (0x01 << 15) ++#define CCDC_FPC_DISABLE (0x0) ++#define CCDC_FPC_FPC_NUM_MASK (0x7FFF) ++#define CCDC_DATA_PACK_ENABLE (0x01<<11) ++#define CCDC_FMTCFG_VPIN_MASK (0x07) ++#define CCDC_FMTCFG_VPIN_SHIFT (12) ++#define CCDC_FMT_HORZ_FMTLNH_MASK (0x1FFF) ++#define CCDC_FMT_HORZ_FMTSPH_MASK (0x1FFF) ++#define CCDC_FMT_HORZ_FMTSPH_SHIFT (16) ++#define CCDC_FMT_VERT_FMTLNV_MASK (0x1FFF) ++#define CCDC_FMT_VERT_FMTSLV_MASK (0x1FFF) ++#define CCDC_FMT_VERT_FMTSLV_SHIFT (16) ++#define CCDC_VP_OUT_VERT_NUM_MASK (0x3FFF) ++#define CCDC_VP_OUT_VERT_NUM_SHIFT (17) ++#define CCDC_VP_OUT_HORZ_NUM_MASK (0x1FFF) ++#define CCDC_VP_OUT_HORZ_NUM_SHIFT (4) ++#define CCDC_VP_OUT_HORZ_ST_MASK (0x000F) ++#define CCDC_HORZ_INFO_SPH_SHIFT (16) ++#define CCDC_VERT_START_SLV0_SHIFT (16) ++#define CCDC_VDINT_VDINT0_SHIFT (16) ++#define CCDC_VDINT_VDINT1_MASK (0xFFFF) ++ ++/* SBL register and mask defination */ ++#define SBL_PCR_VPSS (4) ++#define SBL_PCR_CCDC_WBL_O (0xFF7FFFFF) ++ ++#define PPC_RAW (1) ++#define DCSUB_DEFAULT_VAL (0) ++#define CLAMP_DEFAULT_VAL (0) ++#define ENABLE_VIDEO_PORT (0x00008000) ++#define DISABLE_VIDEO_PORT (0) ++#define CCDC_COLPTN_VAL (0xBB11BB11) ++#define TWO_BYTES_PER_PIXEL (2) ++#define INTERLACED_IMAGE_INVERT (0x4B6D) ++#define INTERLACED_NO_IMAGE_INVERT (0x0249) ++#define PROGRESSIVE_IMAGE_INVERT (0x4000) ++#define PROGRESSIVE_NO_IMAGE_INVERT (0) ++#define CCDC_INTERLACED_HEIGHT_SHIFT (1) ++ ++#endif ++#endif /* CCDC_DAVINCI_H */ +diff --git a/include/media/ccdc_davinci.h b/include/media/ccdc_davinci.h +deleted file mode 100644 +index 9f0a08d..0000000 +--- a/include/media/ccdc_davinci.h ++++ /dev/null +@@ -1,144 +0,0 @@ +-/* +- * +- * Copyright (C) 2006 Texas Instruments Inc +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- */ +-/* ccdc_davinci.h */ +- +-#ifndef CCDC_DAVINCI_H +-#define CCDC_DAVINCI_H +-#include <linux/types.h> +- +-#ifdef __KERNEL__ +-#include <asm/arch/hardware.h> +-#include <asm/io.h> +-#endif +- +-#include <linux/videodev.h> +- +-typedef enum ccdc_pixfmt { +- CCDC_PIXFMT_RAW = 0, +- CCDC_PIXFMT_YCBCR_16BIT = 1, +- CCDC_PIXFMT_YCBCR_8BIT = 2 +-} ccdc_pixfmt; +- +-typedef enum ccdc_frmfmt { +- CCDC_FRMFMT_PROGRESSIVE = 0, +- CCDC_FRMFMT_INTERLACED = 1 +-} ccdc_frmfmt; +- +-typedef enum ccdc_pinpol { +- CCDC_PINPOL_POSITIVE = 0, +- CCDC_PINPOL_NEGATIVE = 1 +-} ccdc_pinpol; +- +-/* PIXEL ORDER IN MEMORY from LSB to MSB */ +-/* only applicable for 8-bit input mode */ +-typedef enum ccdc_pixorder { +- CCDC_PIXORDER_CBYCRY = 1, +- CCDC_PIXORDER_YCBYCR = 0 +-} ccdc_pixorder; +- +-typedef enum ccdc_buftype { +- CCDC_BUFTYPE_FLD_INTERLEAVED, +- CCDC_BUFTYPE_FLD_SEPARATED +-} ccdc_buftype; +- +-typedef struct v4l2_rect ccdc_imgwin; +- +-typedef struct ccdc_params_ycbcr { +- ccdc_pixfmt pix_fmt; /* pixel format */ +- ccdc_frmfmt frm_fmt; /* progressive or interlaced frame */ +- ccdc_imgwin win; /* video window */ +- ccdc_pinpol fid_pol; /* field id polarity */ +- ccdc_pinpol vd_pol; /* vertical sync polarity */ +- ccdc_pinpol hd_pol; /* horizontal sync polarity */ +- int bt656_enable; /* enable BT.656 embedded sync mode */ +- ccdc_pixorder pix_order;/* cb:y:cr:y or y:cb:y:cr in memory */ +- ccdc_buftype buf_type; /* interleaved or separated fields */ +-} ccdc_params_ycbcr; +- +-#ifdef __KERNEL__ +-/**************************************************************************\ +-* Register OFFSET Definitions +-\**************************************************************************/ +-#define PID 0x0 +-#define PCR 0x4 +-#define SYN_MODE 0x8 +-#define HD_VD_WID 0xc +-#define PIX_LINES 0x10 +-#define HORZ_INFO 0x14 +-#define VERT_START 0x18 +-#define VERT_LINES 0x1c +-#define CULLING 0x20 +-#define HSIZE_OFF 0x24 +-#define SDOFST 0x28 +-#define SDR_ADDR 0x2c +-#define CLAMP 0x30 +-#define DCSUB 0x34 +-#define COLPTN 0x38 +-#define BLKCMP 0x3c +-#define FPC 0x40 +-#define FPC_ADDR 0x44 +-#define VDINT 0x48 +-#define ALAW 0x4c +-#define REC656IF 0x50 +-#define CCDCFG 0x54 +-#define FMTCFG 0x58 +-#define FMT_HORZ 0x5c +-#define FMT_VERT 0x50 +-#define FMT_ADDR0 0x64 +-#define FMT_ADDR1 0x68 +-#define FMT_ADDR2 0x6c +-#define FMT_ADDR3 0x70 +-#define FMT_ADDR4 0x74 +-#define FMT_ADDR5 0x78 +-#define FMT_ADDR6 0x7c +-#define FMT_ADDR7 0x80 +-#define PRGEVEN_0 0x84 +-#define PRGEVEN_1 0x88 +-#define PRGODD_0 0x8c +-#define PRGODD_1 0x90 +-#define VP_OUT 0x94 +- +-#define CCDC_IOBASE (0x01c70400) +- +-#define regw(val, reg) davinci_writel(val, (reg)+CCDC_IOBASE) +-#define regr(reg) davinci_readl((reg)+CCDC_IOBASE) +- +-extern void ccdc_reset(void); +-extern void ccdc_config_ycbcr(ccdc_params_ycbcr * params); +-extern void ccdc_setwin(ccdc_params_ycbcr * params); +- +-/* inline functions that must be fast because they are called frequently */ +-static inline void ccdc_enable(int flag) +-{ +- regw(flag, PCR); +-} +- +-static inline void ccdc_setfbaddr(unsigned long paddr) +-{ +- regw(paddr & 0xffffffe0, SDR_ADDR); +-} +- +-static inline int ccdc_getfid(void) +-{ +- int fid = (regr(SYN_MODE) >> 15) & 0x1; +- return fid; +-} +-#endif +- +-#endif /* CCDC_DAVINCI_H */ +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci/vfpe5.patch b/recipes/linux/linux-davinci/vfpe5.patch new file mode 100644 index 0000000000..160908a1cd --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe5.patch @@ -0,0 +1,132 @@ +Subject: +[PATCH 5/7] Kconfig and Makefile changes for vpfe capture driver +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:23:32 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Adding updates to video Kconfig and Makefile and adding +Makefile for building vpfe-capture files + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + drivers/media/video/Kconfig | 48 ++++++++++++++++++++++++---------- + drivers/media/video/Makefile | 6 +--- + drivers/media/video/davinci/Makefile | 8 +++++ + 3 files changed, 43 insertions(+), 19 deletions(-) + create mode 100644 drivers/media/video/davinci/Makefile + +diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig +index 1dd98d8..ea3a526 100644 +--- a/drivers/media/video/Kconfig ++++ b/drivers/media/video/Kconfig +@@ -485,25 +485,45 @@ config VIDEO_VIVI + Say Y here if you want to test video apps or debug V4L devices. + In doubt, say N. + +-config VIDEO_TVP5146 +- tristate "TVP5146 video decoder" +- depends on I2C && ARCH_DAVINCI ++config VIDEO_VPFE_CAPTURE ++ tristate "VPFE Video Capture Driver" ++ depends on VIDEO_V4L2 && ARCH_DAVINCI ++ select VIDEOBUF_DMA_CONTIG + help +- Support for I2C bus based TVP5146 configuration. ++ Support for DMXXXX VPFE based frame grabber. This is the ++ common V4L2 module for following DMXXX SoCs from Texas ++ Instruments:- DM6446 & DM355. + + To compile this driver as a module, choose M here: the +- module will be called tvp5146. ++ module will be called vpfe-capture. + +-config VIDEO_DAVINCI +- tristate "Davinci Video Capture" +- depends on VIDEO_DEV && VIDEO_TVP5146 && ARCH_DAVINCI +- select VIDEOBUF_GEN +- select VIDEOBUF_DMA_SG ++config VIDEO_DAVINCI_CCDC ++ tristate "DM6446 CCDC HW module" ++ depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE ++ default y + help +- Support for Davinci based frame grabber through CCDC. +- +- To compile this driver as a module, choose M here: the +- module will be called vpfe. ++ Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces ++ with decoder modules such as TVP5146 over BT656 or ++ sensor module such as MT9T001 over a raw interface. This ++ module configures the interface and CCDC/ISIF to do ++ video frame capture from slave decoders. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called vpfe. ++ ++config VIDEO_DM355_CCDC ++ tristate "DM355 CCDC HW module" ++ depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE ++ default y ++ help ++ Enables DM355 CCD hw module. DM355 CCDC hw interfaces ++ with decoder modules such as TVP5146 over BT656 or ++ sensor module such as MT9T001 over a raw interface. This ++ module configures the interface and CCDC/ISIF to do ++ video frame capture from a slave decoders ++ ++ To compile this driver as a module, choose M here: the ++ module will be called vpfe. + + source "drivers/media/video/bt8xx/Kconfig" + +diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile +index 863b5c8..f8b6c0c 100644 +--- a/drivers/media/video/Makefile ++++ b/drivers/media/video/Makefile +@@ -10,8 +10,6 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o + + omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o + +-davinci-vpfe-objs := ccdc_davinci.o davinci_vpfe.o +- + videodev-objs := v4l2-dev.o v4l2-ioctl.o + + videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o +@@ -29,6 +27,7 @@ endif + + obj-$(CONFIG_VIDEO_TUNER) += tuner.o + ++obj-$(CONFIG_ARCH_DAVINCI) += davinci/ + obj-$(CONFIG_VIDEO_BT848) += bt8xx/ + obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o + obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o +@@ -135,9 +134,6 @@ obj-$(CONFIG_USB_S2255) += s2255drv.o + obj-$(CONFIG_VIDEO_IVTV) += ivtv/ + obj-$(CONFIG_VIDEO_CX18) += cx18/ + +-obj-$(CONFIG_VIDEO_DAVINCI) += davinci-vpfe.o +-obj-$(CONFIG_VIDEO_TVP5146) += tvp5146.o +- + obj-$(CONFIG_VIDEO_VIVI) += vivi.o + obj-$(CONFIG_VIDEO_CX23885) += cx23885/ + +diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile +new file mode 100644 +index 0000000..77fe038 +--- /dev/null ++++ b/drivers/media/video/davinci/Makefile +@@ -0,0 +1,8 @@ ++# ++# Makefile for the davinci video device drivers. ++# ++ ++# Capture: DaVinci and DM355 ++obj-$(CONFIG_VIDEO_DAVINCI_CCDC) += ccdc_davinci.o ++obj-$(CONFIG_VIDEO_DM355_CCDC) += ccdc_dm355.o ++obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci/vfpe6.patch b/recipes/linux/linux-davinci/vfpe6.patch new file mode 100644 index 0000000000..b425eea5dd --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe6.patch @@ -0,0 +1,224 @@ +Subject: +[PATCH 6/7] platform-related-updates for vpfe capture driver on DM6446 +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:24:04 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Add platform related changes for vpfe capture driver on DM6446 + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + arch/arm/mach-davinci/board-dm644x-evm.c | 88 ++++++++++++++++++++++++++- + arch/arm/mach-davinci/dm644x.c | 42 +++++++++++++ + arch/arm/mach-davinci/include/mach/dm644x.h | 2 + + 3 files changed, 130 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c +index 20ec961..5f4d9a8 100644 +--- a/arch/arm/mach-davinci/board-dm644x-evm.c ++++ b/arch/arm/mach-davinci/board-dm644x-evm.c +@@ -27,7 +27,9 @@ + #include <linux/io.h> + #include <linux/phy.h> + #include <linux/clk.h> +- ++#include <linux/videodev2.h> ++#include <media/v4l2-int-device.h> ++#include <media/tvp514x.h> + #include <asm/setup.h> + #include <asm/mach-types.h> + +@@ -161,6 +163,41 @@ static struct platform_device davinci_fb_device = { + .num_resources = 0, + }; + ++ ++#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) ++static struct vpfe_capture_input vpfe_capture_inputs = { ++ .num_inputs = VPFE_MAX_DEC_INPUTS, ++ .current_input = 0, ++ .inputs[0] = { ++ .dec_name = TVP514X_MODULE_NAME, ++ .input = { ++ .index = 0, ++ .name = "COMPOSITE", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .std = TVP514X_STD_ALL, ++ }, ++ .route = { ++ .input = INPUT_CVBS_VI2B, ++ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, ++ }, ++ .routing_supported = 1, ++ }, ++ .inputs[1] = { ++ .dec_name = TVP514X_MODULE_NAME, ++ .input = { ++ .index = 1, ++ .name = "SVIDEO", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .std = TVP514X_STD_ALL, ++ }, ++ .route = { ++ .input = INPUT_SVIDEO_VI2C_VI1C, ++ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, ++ }, ++ .routing_supported = 1, ++ }, ++}; ++ + static struct platform_device rtc_dev = { + .name = "rtc_davinci_evm", + .id = -1, +@@ -447,6 +484,48 @@ int dm6446evm_eeprom_write(void *buf, off_t off, size_t count) + } + EXPORT_SYMBOL(dm6446evm_eeprom_write); + ++#define TVP5146_I2C_ADDR (0x5D) ++static struct v4l2_ifparm tvp5146_ifparm = { ++ .if_type = V4L2_IF_TYPE_BT656, ++ .u = { ++ .bt656 = { ++ .frame_start_on_rising_vs = 1, ++ .bt_sync_correct = 0, ++ .swap = 0, ++ .latch_clk_inv = 0, ++ .nobt_hs_inv = 0, /* active high */ ++ .nobt_vs_inv = 0, /* active high */ ++ .mode = V4L2_IF_TYPE_BT656_MODE_BT_8BIT, ++ .clock_min = TVP514X_XCLK_BT656, ++ .clock_max = TVP514X_XCLK_BT656, ++ }, ++ }, ++}; ++ ++/** ++ * @brief tvp5146_g_ifparm - Returns the TVP5146 decoder interface parameters ++ * ++ * @param p - pointer to v4l2_ifparm structure ++ * @return result of operation - 0 is success ++ */ ++static int tvp5146_g_ifparm(struct v4l2_ifparm *p) ++{ ++ if (p == NULL) ++ return -EINVAL; ++ ++ *p = tvp5146_ifparm; ++ return 0; ++} ++ ++#define TVP5146_NUM_INPUTS ARRAY_SIZE(tvp5146_input_list) ++ ++static struct tvp514x_platform_data tvp5146_pdata = { ++ .master = CAPTURE_DRV_NAME, ++ .ifparm = tvp5146_g_ifparm, ++ .hs_polarity = 1, ++ .vs_polarity = 1 ++}; ++ + /* + * MSP430 supports RTC, card detection, input from IR remote, and + * a bit more. It triggers interrupts on GPIO(7) from pressing +@@ -557,9 +636,12 @@ static struct i2c_board_info __initdata i2c_info[] = { + I2C_BOARD_INFO("24c256", 0x50), + .platform_data = &eeprom_info, + }, ++ { ++ I2C_BOARD_INFO("tvp5146", TVP5146_I2C_ADDR), ++ .platform_data = &tvp5146_pdata, ++ }, + /* ALSO: + * - tvl320aic33 audio codec (0x1b) +- * - tvp5146 video decoder (0x5d) + */ + }; + +@@ -591,6 +673,8 @@ static void __init + davinci_evm_map_io(void) + { + davinci_map_common_io(); ++ /* setup input configuration for VPFE input devices */ ++ setup_vpfe_input_config(&vpfe_capture_inputs); + dm644x_init(); + } + +diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c +index 03946fd..f46095e 100644 +--- a/arch/arm/mach-davinci/dm644x.c ++++ b/arch/arm/mach-davinci/dm644x.c +@@ -419,6 +419,46 @@ static struct platform_device dm644x_edma_device = { + .resource = edma_resources, + }; + ++static struct resource vpfe_resources[] = { ++ { ++ .start = IRQ_VDINT0, ++ .end = IRQ_VDINT0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = IRQ_VDINT1, ++ .end = IRQ_VDINT1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = 0x01c70400, ++ .end = 0x01c70400 + 0xff, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = 0x01c73400, ++ .end = 0x01c73400 + 0xff, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static u64 vpfe_capture_dma_mask = DMA_32BIT_MASK; ++static struct platform_device vpfe_capture_dev = { ++ .name = CAPTURE_DRV_NAME, ++ .id = -1, ++ .num_resources = ARRAY_SIZE(vpfe_resources), ++ .resource = vpfe_resources, ++ .dev = { ++ .dma_mask = &vpfe_capture_dma_mask, ++ .coherent_dma_mask = DMA_32BIT_MASK, ++ }, ++}; ++ ++void setup_vpfe_input_config(struct vpfe_capture_input *input_config) ++{ ++ vpfe_capture_dev.dev.platform_data = input_config; ++} ++ + /*----------------------------------------------------------------------*/ + + void __init dm644x_init(void) +@@ -433,6 +473,8 @@ static int __init dm644x_init_devices(void) + return 0; + + platform_device_register(&dm644x_edma_device); ++ /* Register VPFE capture device */ ++ platform_device_register(&vpfe_capture_dev); + return 0; + } + postcore_initcall(dm644x_init_devices); +diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h +index 5b3d512..14f9a8a 100644 +--- a/arch/arm/mach-davinci/include/mach/dm644x.h ++++ b/arch/arm/mach-davinci/include/mach/dm644x.h +@@ -23,7 +23,9 @@ + #define __ASM_ARCH_DM644X_H + + #include <mach/hardware.h> ++#include <media/davinci/vpfe_capture.h> + + void __init dm644x_init(void); ++void setup_vpfe_input_config(struct vpfe_capture_input *input_config); + + #endif /* __ASM_ARCH_DM644X_H */ +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci/vfpe7.patch b/recipes/linux/linux-davinci/vfpe7.patch new file mode 100644 index 0000000000..a6695a8cda --- /dev/null +++ b/recipes/linux/linux-davinci/vfpe7.patch @@ -0,0 +1,283 @@ +Subject: +[PATCH 7/7] DM355 platform related changes for vpfe capture driver +From: +m-karicheri2-l0cyMroinI0@public.gmane.org +Date: +Fri, 13 Mar 2009 17:24:34 -0400 +To: +davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org, davinci_opensource_ccb-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org, psp_video-uAqBSO/uNfhBDgjK7y7TUQ@public.gmane.org +Newsgroups: +gmane.linux.davinci + +Add platform related changes for vpfe capture driver on DM355 + +Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org> +--- + arch/arm/mach-davinci/board-dm355-evm.c | 91 +++++++++++++++++++++++++++- + arch/arm/mach-davinci/dm355.c | 64 +++++++++++++++++++ + arch/arm/mach-davinci/include/mach/dm355.h | 2 + + arch/arm/mach-davinci/include/mach/mux.h | 9 +++ + 4 files changed, 163 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c +index e104650..aaa58ba 100644 +--- a/arch/arm/mach-davinci/board-dm355-evm.c ++++ b/arch/arm/mach-davinci/board-dm355-evm.c +@@ -20,6 +20,8 @@ + #include <linux/io.h> + #include <linux/gpio.h> + #include <linux/clk.h> ++#include <media/v4l2-int-device.h> ++#include <media/tvp514x.h> + #include <linux/spi/spi.h> + #include <linux/spi/eeprom.h> + +@@ -134,12 +136,58 @@ static void dm355evm_mmcsd_gpios(unsigned gpio) + dm355evm_mmc_gpios = gpio; + } + ++#define TVP5146_I2C_ADDR 0x5D ++static struct v4l2_ifparm tvp5146_ifparm = { ++ .if_type = V4L2_IF_TYPE_BT656, ++ .u = { ++ .bt656 = { ++ .frame_start_on_rising_vs = 1, ++ .bt_sync_correct = 0, ++ .swap = 0, ++ .latch_clk_inv = 0, ++ .nobt_hs_inv = 0, /* active high */ ++ .nobt_vs_inv = 0, /* active high */ ++ .mode = V4L2_IF_TYPE_BT656_MODE_BT_8BIT, ++ .clock_min = TVP514X_XCLK_BT656, ++ .clock_max = TVP514X_XCLK_BT656, ++ }, ++ }, ++}; ++ ++/** ++ * @brief tvp5146_g_ifparm - Returns the TVP5146 decoder interface parameters ++ * ++ * @param p - pointer to v4l2_ifparm structure ++ * @return result of operation - 0 is success ++ */ ++static int tvp5146_g_ifparm(struct v4l2_ifparm *p) ++{ ++ if (p == NULL) ++ return -EINVAL; ++ ++ *p = tvp5146_ifparm; ++ return 0; ++} ++ ++#define TVP5146_NUM_INPUTS ARRAY_SIZE(tvp5146_input_list) ++ ++static struct tvp514x_platform_data tvp5146_pdata = { ++ .master = CAPTURE_DRV_NAME, ++ .ifparm = tvp5146_g_ifparm, ++ .hs_polarity = 1, ++ .vs_polarity = 1 ++}; ++ + static struct i2c_board_info dm355evm_i2c_info[] = { +- { I2C_BOARD_INFO("dm355evm_msp", 0x25), ++ { I2C_BOARD_INFO("dm355evm_msp", 0x25), + .platform_data = dm355evm_mmcsd_gpios, +- /* plus irq */ }, ++ }, ++ { ++ I2C_BOARD_INFO("tvp5146", TVP5146_I2C_ADDR), ++ .platform_data = &tvp5146_pdata, ++ }, ++ /* { plus irq }, */ + /* { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }, */ +- /* { I2C_BOARD_INFO("tvp5146", 0x5d), }, */ + }; + + static void __init evm_init_i2c(void) +@@ -178,6 +226,41 @@ static struct platform_device dm355evm_dm9000 = { + .num_resources = ARRAY_SIZE(dm355evm_dm9000_rsrc), + }; + ++#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) ++ ++static struct vpfe_capture_input vpfe_capture_inputs = { ++ .num_inputs = VPFE_MAX_DEC_INPUTS, ++ .current_input = 0, ++ .inputs[0] = { ++ .dec_name = TVP514X_MODULE_NAME, ++ .input = { ++ .index = 0, ++ .name = "COMPOSITE", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .std = TVP514X_STD_ALL, ++ }, ++ .route = { ++ .input = INPUT_CVBS_VI2B, ++ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, ++ }, ++ .routing_supported = 1, ++ }, ++ .inputs[1] = { ++ .dec_name = TVP514X_MODULE_NAME, ++ .input = { ++ .index = 1, ++ .name = "SVIDEO", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .std = TVP514X_STD_ALL, ++ }, ++ .route = { ++ .input = INPUT_SVIDEO_VI2C_VI1C, ++ .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, ++ }, ++ .routing_supported = 1, ++ }, ++}; ++ + static struct platform_device *davinci_evm_devices[] __initdata = { + &dm355evm_dm9000, + &davinci_nand_device, +@@ -190,6 +273,8 @@ static struct davinci_uart_config uart_config __initdata = { + static void __init dm355_evm_map_io(void) + { + davinci_map_common_io(); ++ /* setup input configuration for VPFE input devices */ ++ setup_vpfe_input_config(&vpfe_capture_inputs); + dm355_init(); + } + +diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c +index 5f31649..e2612dd 100644 +--- a/arch/arm/mach-davinci/dm355.c ++++ b/arch/arm/mach-davinci/dm355.c +@@ -463,6 +463,14 @@ INT_CFG(DM355, INT_EDMA_TC1_ERR, 4, 1, 1, false) + EVT_CFG(DM355, EVT8_ASP1_TX, 0, 1, 0, false) + EVT_CFG(DM355, EVT9_ASP1_RX, 1, 1, 0, false) + EVT_CFG(DM355, EVT26_MMC0_RX, 2, 1, 0, false) ++ ++MUX_CFG(DM355, VIN_PCLK, 0, 14, 1, 1, false) ++MUX_CFG(DM355, VIN_CAM_WEN, 0, 13, 1, 1, false) ++MUX_CFG(DM355, VIN_CAM_VD, 0, 12, 1, 1, false) ++MUX_CFG(DM355, VIN_CAM_HD, 0, 11, 1, 1, false) ++MUX_CFG(DM355, VIN_YIN_EN, 0, 10, 1, 1, false) ++MUX_CFG(DM355, VIN_CINL_EN, 0, 0, 0xff, 0x55, false) ++MUX_CFG(DM355, VIN_CINH_EN, 0, 8, 3, 3, false) + }; + + /*----------------------------------------------------------------------*/ +@@ -520,6 +528,47 @@ static struct platform_device dm355_edma_device = { + .resource = edma_resources, + }; + ++static struct resource vpfe_resources[] = { ++ { ++ .start = IRQ_VDINT0, ++ .end = IRQ_VDINT0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = IRQ_VDINT1, ++ .end = IRQ_VDINT1, ++ .flags = IORESOURCE_IRQ, ++ }, ++ /* CCDC Base address */ ++ { ++ .flags = IORESOURCE_MEM, ++ .start = 0x01c70600, ++ .end = 0x01c70600 + 0x1ff, ++ }, ++ /* VPSS Base address */ ++ { ++ .start = 0x01c70800, ++ .end = 0x01c70800 + 0xff, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++static u64 vpfe_capture_dma_mask = DMA_32BIT_MASK; ++static struct platform_device vpfe_capture_dev = { ++ .name = CAPTURE_DRV_NAME, ++ .id = -1, ++ .num_resources = ARRAY_SIZE(vpfe_resources), ++ .resource = vpfe_resources, ++ .dev = { ++ .dma_mask = &vpfe_capture_dma_mask, ++ .coherent_dma_mask = DMA_32BIT_MASK, ++ }, ++}; ++ ++void setup_vpfe_input_config(struct vpfe_capture_input *input_config) ++{ ++ vpfe_capture_dev.dev.platform_data = input_config; ++} + /*----------------------------------------------------------------------*/ + + void __init dm355_init(void) +@@ -528,13 +577,28 @@ void __init dm355_init(void) + davinci_mux_register(dm355_pins, ARRAY_SIZE(dm355_pins));; + } + ++#define DM355_VPSSCLK_CLKCTRL_REG 0x1c70004 + static int __init dm355_init_devices(void) + { ++ void __iomem *base = IO_ADDRESS(DM355_VPSSCLK_CLKCTRL_REG); + if (!cpu_is_davinci_dm355()) + return 0; + + davinci_cfg_reg(DM355_INT_EDMA_CC); + platform_device_register(&dm355_edma_device); ++ /* setup clock for vpss modules */ ++ __raw_writel(0x79, base); ++ /* setup Mux configuration for vpfe input and register ++ * vpfe capture platform device ++ */ ++ davinci_cfg_reg(DM355_VIN_PCLK); ++ davinci_cfg_reg(DM355_VIN_CAM_WEN); ++ davinci_cfg_reg(DM355_VIN_CAM_VD); ++ davinci_cfg_reg(DM355_VIN_CAM_HD); ++ davinci_cfg_reg(DM355_VIN_YIN_EN); ++ davinci_cfg_reg(DM355_VIN_CINL_EN); ++ davinci_cfg_reg(DM355_VIN_CINH_EN); ++ platform_device_register(&vpfe_capture_dev); + return 0; + } + postcore_initcall(dm355_init_devices); +diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h +index f7100b6..0b3bd76 100644 +--- a/arch/arm/mach-davinci/include/mach/dm355.h ++++ b/arch/arm/mach-davinci/include/mach/dm355.h +@@ -12,6 +12,7 @@ + #define __ASM_ARCH_DM355_H + + #include <mach/hardware.h> ++#include <media/davinci/vpfe_capture.h> + + void __init dm355_init(void); + +@@ -19,5 +20,6 @@ struct spi_board_info; + + void dm355_init_spi0(unsigned chipselect_mask, + struct spi_board_info *info, unsigned len); ++void setup_vpfe_input_config(struct vpfe_capture_input *input_config); + + #endif /* __ASM_ARCH_DM355_H */ +diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h +index cd95629..4c135b0 100644 +--- a/arch/arm/mach-davinci/include/mach/mux.h ++++ b/arch/arm/mach-davinci/include/mach/mux.h +@@ -149,6 +149,15 @@ enum davinci_dm355_index { + DM355_EVT8_ASP1_TX, + DM355_EVT9_ASP1_RX, + DM355_EVT26_MMC0_RX, ++ ++ /* Video In Pin Mux */ ++ DM355_VIN_PCLK, ++ DM355_VIN_CAM_WEN, ++ DM355_VIN_CAM_VD, ++ DM355_VIN_CAM_HD, ++ DM355_VIN_YIN_EN, ++ DM355_VIN_CINL_EN, ++ DM355_VIN_CINH_EN, + }; + + #ifdef CONFIG_DAVINCI_MUX +-- 1.6.0.4
\ No newline at end of file diff --git a/recipes/linux/linux-davinci_git.bb b/recipes/linux/linux-davinci_git.bb index 779f012a4c..332aeb6e04 100644 --- a/recipes/linux/linux-davinci_git.bb +++ b/recipes/linux/linux-davinci_git.bb @@ -10,10 +10,17 @@ DEFAULT_PREFERENCE = "-1" SRCREV = "486afa37130356662213cc1a2199a285b4fd72af" PV = "2.6.29+2.6.29-rc7-${PR}+gitr${SRCREV}" -PR = "r2" +PR = "r3" SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git;protocol=git \ file://update-mach-types.patch;patch=1 \ + file://vfpe1.patch;patch=1 \ + file://vfpe2.patch;patch=1 \ + file://vfpe3.patch;patch=1 \ + file://vfpe4.patch;patch=1 \ + file://vfpe5.patch;patch=1 \ + file://vfpe6.patch;patch=1 \ + file://vfpe7.patch;patch=1 \ file://defconfig" SRC_URI_append_davinci-sffsdr = " \ @@ -33,6 +40,7 @@ SRC_URI_append_davinci-sffsdr = " \ SRC_URI_append_dm355-leopard = " \ file://0001-dm355-leopard-add-board-file-based-on-board-dm355-e.patch;patch=1 \ - " + file://vfpe.patch;patch=1 \ +" S = "${WORKDIR}/git" |