From patchwork Fri Mar 19 09:35:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vaibhav Hiremath X-Patchwork-Id: 87432 Received: from arroyo.ext.ti.com (arroyo.ext.ti.com [192.94.94.40]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2MEDMN2005505 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 22 Mar 2010 14:13:59 GMT Received: from dlep35.itg.ti.com ([157.170.170.118]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id o2ME9xrF031853 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 22 Mar 2010 09:09:59 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep35.itg.ti.com (8.13.7/8.13.7) with ESMTP id o2ME9sYT023016; Mon, 22 Mar 2010 09:09:58 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 42ED780627; Mon, 22 Mar 2010 08:09:54 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dbdp31.itg.ti.com (dbdp31.itg.ti.com [172.24.170.98]) by linux.omap.com (Postfix) with ESMTP id 494FD80626 for ; Fri, 19 Mar 2010 03:36:08 -0600 (CST) Received: from localhost.localdomain (localhost [127.0.0.1]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with ESMTP id o2J9Zogd025140; Fri, 19 Mar 2010 15:05:51 +0530 (IST) From: hvaibhav@ti.com To: linux-media@vger.kernel.org Subject: [Resubmit: PATCH-V2] Introducing ti-media directory Date: Fri, 19 Mar 2010 15:05:50 +0530 Message-Id: <1268991350-549-1-git-send-email-hvaibhav@ti.com> X-Mailer: git-send-email 1.6.2.4 In-Reply-To: References: X-Mailman-Approved-At: Mon, 22 Mar 2010 08:09:49 -0600 Cc: davinci-linux-open-source@linux.davincidsp.com X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 22 Mar 2010 14:14:02 +0000 (UTC) difficuilt to re-use the driver code. For example, DM6446 and AM3517 both uses exactly same VPFE/CCDC IP, but the driver is encapsulated under DAVINCI which makes it impossible to re-use. Signed-off-by: Vaibhav Hiremath --- arch/arm/mach-davinci/include/mach/dm355.h | 2 +- arch/arm/mach-davinci/include/mach/dm365.h | 2 +- arch/arm/mach-davinci/include/mach/dm644x.h | 2 +- drivers/media/video/Kconfig | 96 +- drivers/media/video/Makefile | 2 +- drivers/media/video/davinci/Makefile | 18 - drivers/media/video/davinci/ccdc_hw_device.h | 110 -- drivers/media/video/davinci/dm355_ccdc.c | 1082 ----------- drivers/media/video/davinci/dm355_ccdc_regs.h | 310 ---- drivers/media/video/davinci/dm644x_ccdc.c | 1090 ------------ drivers/media/video/davinci/dm644x_ccdc_regs.h | 153 -- drivers/media/video/davinci/isif.c | 1172 ------------ drivers/media/video/davinci/isif_regs.h | 269 --- drivers/media/video/davinci/vpfe_capture.c | 2080 ---------------------- drivers/media/video/davinci/vpif.c | 296 --- drivers/media/video/davinci/vpif.h | 642 ------- drivers/media/video/davinci/vpif_capture.c | 2168 ---------------------- drivers/media/video/davinci/vpif_capture.h | 165 -- drivers/media/video/davinci/vpif_display.c | 1654 ----------------- drivers/media/video/davinci/vpif_display.h | 175 -- drivers/media/video/davinci/vpss.c | 482 ----- drivers/media/video/ti-media/Kconfig | 100 ++ drivers/media/video/ti-media/Makefile | 18 + drivers/media/video/ti-media/ccdc_hw_device.h | 110 ++ drivers/media/video/ti-media/dm355_ccdc.c | 1086 ++++++++++++ drivers/media/video/ti-media/dm355_ccdc_regs.h | 310 ++++ drivers/media/video/ti-media/dm644x_ccdc.c | 1094 ++++++++++++ drivers/media/video/ti-media/dm644x_ccdc_regs.h | 153 ++ drivers/media/video/ti-media/isif.c | 1172 ++++++++++++ drivers/media/video/ti-media/isif_regs.h | 269 +++ drivers/media/video/ti-media/vpfe_capture.c | 2080 ++++++++++++++++++++++ drivers/media/video/ti-media/vpif.c | 296 +++ drivers/media/video/ti-media/vpif.h | 642 +++++++ drivers/media/video/ti-media/vpif_capture.c | 2169 +++++++++++++++++++++++ drivers/media/video/ti-media/vpif_capture.h | 165 ++ drivers/media/video/ti-media/vpif_display.c | 1654 +++++++++++++++++ drivers/media/video/ti-media/vpif_display.h | 175 ++ drivers/media/video/ti-media/vpss.c | 482 +++++ include/media/davinci/ccdc_types.h | 43 - include/media/davinci/dm355_ccdc.h | 321 ---- include/media/davinci/dm644x_ccdc.h | 184 -- include/media/davinci/isif.h | 531 ------ include/media/davinci/vpfe_capture.h | 202 --- include/media/davinci/vpfe_types.h | 51 - include/media/davinci/vpss.h | 108 -- include/media/ti-media/ccdc_types.h | 43 + include/media/ti-media/dm355_ccdc.h | 321 ++++ include/media/ti-media/dm644x_ccdc.h | 184 ++ include/media/ti-media/isif.h | 531 ++++++ include/media/ti-media/vpfe_capture.h | 202 +++ include/media/ti-media/vpfe_types.h | 51 + include/media/ti-media/vpss.h | 108 ++ 52 files changed, 13421 insertions(+), 13404 deletions(-) delete mode 100644 drivers/media/video/davinci/Makefile delete mode 100644 drivers/media/video/davinci/ccdc_hw_device.h delete mode 100644 drivers/media/video/davinci/dm355_ccdc.c delete mode 100644 drivers/media/video/davinci/dm355_ccdc_regs.h delete mode 100644 drivers/media/video/davinci/dm644x_ccdc.c delete mode 100644 drivers/media/video/davinci/dm644x_ccdc_regs.h delete mode 100644 drivers/media/video/davinci/isif.c delete mode 100644 drivers/media/video/davinci/isif_regs.h delete mode 100644 drivers/media/video/davinci/vpfe_capture.c delete mode 100644 drivers/media/video/davinci/vpif.c delete mode 100644 drivers/media/video/davinci/vpif.h delete mode 100644 drivers/media/video/davinci/vpif_capture.c delete mode 100644 drivers/media/video/davinci/vpif_capture.h delete mode 100644 drivers/media/video/davinci/vpif_display.c delete mode 100644 drivers/media/video/davinci/vpif_display.h delete mode 100644 drivers/media/video/davinci/vpss.c create mode 100644 drivers/media/video/ti-media/Kconfig create mode 100644 drivers/media/video/ti-media/Makefile create mode 100644 drivers/media/video/ti-media/ccdc_hw_device.h create mode 100644 drivers/media/video/ti-media/dm355_ccdc.c create mode 100644 drivers/media/video/ti-media/dm355_ccdc_regs.h create mode 100644 drivers/media/video/ti-media/dm644x_ccdc.c create mode 100644 drivers/media/video/ti-media/dm644x_ccdc_regs.h create mode 100644 drivers/media/video/ti-media/isif.c create mode 100644 drivers/media/video/ti-media/isif_regs.h create mode 100644 drivers/media/video/ti-media/vpfe_capture.c create mode 100644 drivers/media/video/ti-media/vpif.c create mode 100644 drivers/media/video/ti-media/vpif.h create mode 100644 drivers/media/video/ti-media/vpif_capture.c create mode 100644 drivers/media/video/ti-media/vpif_capture.h create mode 100644 drivers/media/video/ti-media/vpif_display.c create mode 100644 drivers/media/video/ti-media/vpif_display.h create mode 100644 drivers/media/video/ti-media/vpss.c delete mode 100644 include/media/davinci/ccdc_types.h delete mode 100644 include/media/davinci/dm355_ccdc.h delete mode 100644 include/media/davinci/dm644x_ccdc.h delete mode 100644 include/media/davinci/isif.h delete mode 100644 include/media/davinci/vpfe_capture.h delete mode 100644 include/media/davinci/vpfe_types.h delete mode 100644 include/media/davinci/vpss.h create mode 100644 include/media/ti-media/ccdc_types.h create mode 100644 include/media/ti-media/dm355_ccdc.h create mode 100644 include/media/ti-media/dm644x_ccdc.h create mode 100644 include/media/ti-media/isif.h create mode 100644 include/media/ti-media/vpfe_capture.h create mode 100644 include/media/ti-media/vpfe_types.h create mode 100644 include/media/ti-media/vpss.h diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h index 85536d8..ffba662 100644 --- a/arch/arm/mach-davinci/include/mach/dm355.h +++ b/arch/arm/mach-davinci/include/mach/dm355.h @@ -13,7 +13,7 @@ #include #include -#include +#include #define ASP1_TX_EVT_EN 1 #define ASP1_RX_EVT_EN 2 diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h index 9fc5a64..a8be084 100644 --- a/arch/arm/mach-davinci/include/mach/dm365.h +++ b/arch/arm/mach-davinci/include/mach/dm365.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #define DM365_EMAC_BASE (0x01D07000) #define DM365_EMAC_CNTRL_OFFSET (0x0000) diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h index 44e8f0f..95f1e65 100644 --- a/arch/arm/mach-davinci/include/mach/dm644x.h +++ b/arch/arm/mach-davinci/include/mach/dm644x.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #define DM644X_EMAC_BASE (0x01C80000) #define DM644X_EMAC_CNTRL_OFFSET (0x0000) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f8fc865..a71326e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -507,39 +507,6 @@ config VIDEO_UPD64083 endmenu # encoder / decoder chips -config DISPLAY_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Display" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG - select VIDEO_DAVINCI_VPIF - select VIDEO_ADV7343 - select VIDEO_THS7303 - help - Support for DM6467 based display device. - - To compile this driver as a module, choose M here: the - module will be called vpif_display. - -config CAPTURE_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Capture" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG - select VIDEO_DAVINCI_VPIF - help - Support for DM6467 based capture device. - - To compile this driver as a module, choose M here: the - module will be called vpif_capture. - -config VIDEO_DAVINCI_VPIF - tristate "DaVinci VPIF Driver" - depends on DISPLAY_DAVINCI_DM646X_EVM - help - Support for DaVinci VPIF Driver. - - To compile this driver as a module, choose M here: the - module will be called vpif. - config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 @@ -552,67 +519,6 @@ config VIDEO_VIVI Say Y here if you want to test video apps or debug V4L devices. In doubt, say N. -config VIDEO_VPSS_SYSTEM - tristate "VPSS System module driver" - depends on ARCH_DAVINCI - help - Support for vpss system module for video driver - -config VIDEO_VPFE_CAPTURE - tristate "VPFE Video Capture Driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI - select VIDEOBUF_DMA_CONTIG - help - 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 vpfe-capture. - -config VIDEO_DM6446_CCDC - tristate "DM6446 CCDC HW module" - depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y - help - 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 - select VIDEO_VPSS_SYSTEM - 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. - -config VIDEO_ISIF - tristate "ISIF HW module" - depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y - help - Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from - a image sensor or YUV data from a YUV source. - - To compile this driver as a module, choose M here: the - module will be called vpfe. - source "drivers/media/video/bt8xx/Kconfig" config VIDEO_PMS @@ -805,6 +711,8 @@ source "drivers/media/video/cx18/Kconfig" source "drivers/media/video/saa7164/Kconfig" +source "drivers/media/video/ti-media/Kconfig" + config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index c51c386..73c0d94 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -167,7 +167,7 @@ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o -obj-$(CONFIG_ARCH_DAVINCI) += davinci/ +obj-$(CONFIG_TI_MEDIA) += ti-media/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile deleted file mode 100644 index a379557..0000000 --- a/drivers/media/video/davinci/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for the davinci video device drivers. -# - -# VPIF -obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o - -#DM646x EVM Display driver -obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o -#DM646x EVM Capture driver -obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o - -# Capture: DM6446 and DM355 -obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o -obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o -obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o -obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o -obj-$(CONFIG_VIDEO_ISIF) += isif.o diff --git a/drivers/media/video/davinci/ccdc_hw_device.h b/drivers/media/video/davinci/ccdc_hw_device.h deleted file mode 100644 index 86b9b35..0000000 --- a/drivers/media/video/davinci/ccdc_hw_device.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 - * - * ccdc device API - */ -#ifndef _CCDC_HW_DEVICE_H -#define _CCDC_HW_DEVICE_H - -#ifdef __KERNEL__ -#include -#include -#include -#include - -/* - * ccdc hw operations - */ -struct ccdc_hw_ops { - /* Pointer to initialize function to initialize ccdc device */ - int (*open) (struct device *dev); - /* Pointer to deinitialize function */ - int (*close) (struct device *dev); - /* set ccdc base address */ - void (*set_ccdc_base)(void *base, int size); - /* Pointer to function to enable or disable ccdc */ - void (*enable) (int en); - /* reset sbl. only for 6446 */ - void (*reset) (void); - /* enable output to sdram */ - void (*enable_out_to_sdram) (int en); - /* Pointer to function to set hw parameters */ - int (*set_hw_if_params) (struct vpfe_hw_if_param *param); - /* 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 (*set_params) (void *params); - /* - * Pointer to function to get parameter. Used - * for implementing VPFE_G_CCDC_PARAMS - */ - int (*get_params) (void *params); - /* Pointer to function to configure ccdc */ - int (*configure) (void); - - /* Pointer to function to set buffer type */ - int (*set_buftype) (enum ccdc_buftype buf_type); - /* Pointer to function to get buffer type */ - enum ccdc_buftype (*get_buftype) (void); - /* Pointer to function to set frame format */ - int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); - /* Pointer to function to get frame format */ - enum ccdc_frmfmt (*get_frame_format) (void); - /* enumerate hw pix formats */ - int (*enum_pix)(u32 *hw_pix, int i); - /* Pointer to function to set buffer type */ - u32 (*get_pixel_format) (void); - /* Pointer to function to get pixel format. */ - int (*set_pixel_format) (u32 pixfmt); - /* Pointer to function to set image window */ - int (*set_image_window) (struct v4l2_rect *win); - /* Pointer to function to set image window */ - void (*get_image_window) (struct v4l2_rect *win); - /* Pointer to function to get line length */ - unsigned int (*get_line_length) (void); - - /* Query CCDC control IDs */ - int (*queryctrl)(struct v4l2_queryctrl *qctrl); - /* Set CCDC control */ - int (*set_control)(struct v4l2_control *ctrl); - /* Get CCDC control */ - int (*get_control)(struct v4l2_control *ctrl); - - /* Pointer to function to set frame buffer address */ - void (*setfbaddr) (unsigned long addr); - /* Pointer to function to get field id */ - int (*getfid) (void); -}; - -struct ccdc_hw_device { - /* ccdc device name */ - char name[32]; - /* module owner */ - struct module *owner; - /* hw ops */ - struct ccdc_hw_ops hw_ops; -}; - -/* Used by CCDC module to register & unregister with vpfe capture driver */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); - -#endif -#endif diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c deleted file mode 100644 index c29ac88..0000000 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ /dev/null @@ -1,1082 +0,0 @@ -/* - * 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 - * - * CCDC hardware module for DM355 - * ------------------------------ - * - * This module is for configuring DM355 CCD controller of VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Bayer RGB data, before writing it to SDRAM. This - * module also allows application to configure individual - * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. - * To do so, application include dm355_ccdc.h and vpfe_capture.h header - * files. The setparams() API is called by vpfe_capture driver - * to configure module parameters - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Split module parameter structure to module specific ioctl structs - * 3) add support for lense shading correction - * 4) investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "dm355_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM355"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* Master clock */ - struct clk *mclk; - /* slave clock */ - struct clk *sclk; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = 256, - .gb_g = 256, - .gr_cy = 256, - .b_mg = 256 - }, - .config_params = { - .datasft = 2, - .mfilt1 = CCDC_NO_MEDIAN_FILTER1, - .mfilt2 = CCDC_NO_MEDIAN_FILTER2, - .alaw = { - .gama_wd = 2, - }, - .blk_clamp = { - .sample_pixel = 1, - .dc_sub = 25 - }, - .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 - }, - }, - }, - /* YCbCr configuration */ - .ycbcr = { - .win = CCDC_WIN_PAL, - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~CCDC_SYNCEN_VDHDEN_MASK); - temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_enable_output_to_sdram(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~(CCDC_SYNCEN_WEN_MASK)); - temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_config_gain_offset(void) -{ - /* configure gain */ - regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); - regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); - regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); - regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); - /* configure offset */ - regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); -} - -/* - * ccdc_restore_defaults() - * This function restore power on defaults in the ccdc registers - */ -static int ccdc_restore_defaults(void) -{ - int i; - - dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); - /* set all registers to zero */ - for (i = 0; i <= CCDC_REG_LAST; i += 4) - regw(0, i); - - /* now override the values with power on defaults in registers */ - regw(MODESET_DEFAULT, MODESET); - /* no culling support */ - regw(CULH_DEFAULT, CULH); - regw(CULV_DEFAULT, CULV); - /* Set default Gain and Offset */ - ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; - ccdc_config_gain_offset(); - regw(OUTCLIP_DEFAULT, OUTCLIP); - regw(LSCCFG2_DEFAULT, LSCCFG2); - /* select ccdc input */ - if (vpss_select_ccdc_source(VPSS_CCDCIN)) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); - return -EFAULT; - } - /* select ccdc clock */ - if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); - return -EFAULT; - } - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); - return 0; -} - -static int ccdc_open(struct device *device) -{ - return ccdc_restore_defaults(); -} - -static int ccdc_close(struct device *device) -{ - /* disable clock */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 0); - /* do nothing for now */ - return 0; -} -/* - * ccdc_setwin() - * This function will configure the window size to - * be capture in CCDC reg. - */ -static void ccdc_setwin(struct v4l2_rect *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(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - 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, SPH); - regw(horz_nr_pixels, NPH); - 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 and VDINT1 */ - regw(vert_start, VDINT0); - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - 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 & CCDC_START_VER_ONE_MASK, SLV0); - regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) -{ - if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || - ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { - dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); - return -EINVAL; - } - - if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || - ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { - dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); - return -EINVAL; - } - - if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || - ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { - dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); - return -EINVAL; - } - - if ((ccdcparam->med_filt_thres < 0) || - (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { - dev_dbg(ccdc_cfg.dev, - "Invalid value of median filter thresold\n"); - return -EINVAL; - } - - if (ccdcparam->data_sz < CCDC_DATA_16BITS || - ccdcparam->data_sz > CCDC_DATA_8BITS) { - dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); - return -EINVAL; - } - - if (ccdcparam->alaw.enable) { - if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || - ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { - dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); - return -EINVAL; - } - } - - if (ccdcparam->blk_clamp.b_clamp_enable) { - if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || - ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { - dev_dbg(ccdc_cfg.dev, - "Invalid value of sample pixel\n"); - return -EINVAL; - } - if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || - ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { - dev_dbg(ccdc_cfg.dev, - "Invalid value of sample lines\n"); - return -EINVAL; - } - } - return 0; -} - -/* Parameter operations */ -static int ccdc_set_params(void __user *params) -{ - struct ccdc_config_params_raw ccdc_raw_params; - int x; - - /* only raw module parameters can be set through the IOCTL */ - if (ccdc_cfg.if_type != VPFE_RAW_BAYER) - return -EINVAL; - - x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); - if (x) { - dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" - "params, %d\n", x); - return -EFAULT; - } - - if (!validate_ccdc_param(&ccdc_raw_params)) { - memcpy(&ccdc_cfg.bayer.config_params, - &ccdc_raw_params, - sizeof(ccdc_raw_params)); - return 0; - } - return -EINVAL; -} - -/* This function will configure CCDC for YCbCr video capture */ -static void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 temp; - - /* first set the CCDC power on defaults values in all registers */ - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - ccdc_restore_defaults(); - - /* configure pixel format & video frame format */ - temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << - CCDC_INPUT_MODE_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << - CCDC_FRM_FMT_SHIFT)); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, REC656IF); - /* - * configure the FID, VD, HD pin polarity fld,hd pol positive, - * vd negative, 8-bit pack mode - */ - temp |= CCDC_VD_POL_NEGATIVE; - } else { /* y/c external sync mode */ - temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - - /* pack the data to 8-bit */ - temp |= CCDC_DATA_PACK_ENABLE; - - regw(temp, MODESET); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* configure the order of y cb cr in SD-RAM */ - temp = (params->pix_order << CCDC_Y8POS_SHIFT); - temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; - regw(temp, 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) >> 5), HSIZE); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); - } - - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -/* - * ccdc_config_black_clamp() - * configure parameters for Optical Black Clamp - */ -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->b_clamp_enable) { - /* configure DCSub */ - regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); - regw(0x0000, CLAMP); - return; - } - /* Enable the Black clamping, set sample lines and pixels */ - val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; - regw(val, CLAMP); - - /* If Black clamping is enable then make dcsub 0 */ - val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) - << CCDC_NUM_LINE_CALC_SHIFT; - regw(val, DCSUB); -} - -/* - * ccdc_config_black_compense() - * configure parameters for Black Compensation - */ -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = (bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT); - regw(val, BLKCMP1); - - val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT); - regw(val, BLKCMP0); -} - -/* - * ccdc_write_dfc_entry() - * write an entry in the dfc table. - */ -int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) -{ -/* TODO This is to be re-visited and adjusted */ -#define DFC_WRITE_WAIT_COUNT 1000 - u32 val, count = DFC_WRITE_WAIT_COUNT; - - regw(dfc->dft_corr_vert[index], DFCMEM0); - regw(dfc->dft_corr_horz[index], DFCMEM1); - regw(dfc->dft_corr_sub1[index], DFCMEM2); - regw(dfc->dft_corr_sub2[index], DFCMEM3); - regw(dfc->dft_corr_sub3[index], DFCMEM4); - /* set WR bit to write */ - val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; - regw(val, DFCMEMCTL); - - /* - * Assume, it is very short. If we get an error, we need to - * adjust this value - */ - while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) - count--; - /* - * TODO We expect the count to be non-zero to be successful. Adjust - * the count if write requires more time - */ - - if (count) { - dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - return 0; -} - -/* - * ccdc_config_vdfc() - * configure parameters for Vertical Defect Correction - */ -static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) -{ - u32 val; - int i; - - /* Configure General Defect Correction. The table used is from IPIPE */ - val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; - - /* Configure Vertical Defect Correction if needed */ - if (!dfc->ver_dft_en) { - /* Enable only General Defect Correction */ - regw(val, DFCCTL); - return 0; - } - - if (dfc->table_size > CCDC_DFT_TABLE_SIZE) - return -EINVAL; - - val |= CCDC_DFCCTL_VDFC_DISABLE; - val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << - CCDC_DFCCTL_VDFCSL_SHIFT; - val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << - CCDC_DFCCTL_VDFCUDA_SHIFT; - val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << - CCDC_DFCCTL_VDFLSFT_SHIFT; - regw(val , DFCCTL); - - /* clear address ptr to offset 0 */ - val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; - - /* write defect table entries */ - for (i = 0; i < dfc->table_size; i++) { - /* increment address for non zero index */ - if (i != 0) - val = CCDC_DFCMEMCTL_INC_ADDR; - regw(val, DFCMEMCTL); - if (ccdc_write_dfc_entry(i, dfc) < 0) - return -EFAULT; - } - - /* update saturation level and enable dfc */ - regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); - val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << - CCDC_DFCCTL_VDFCEN_SHIFT); - regw(val, DFCCTL); - return 0; -} - -/* - * ccdc_config_csc() - * configure parameters for color space conversion - * Each register CSCM0-7 has two values in S8Q5 format. - */ -static void ccdc_config_csc(struct ccdc_csc *csc) -{ - u32 val1, val2; - int i; - - if (!csc->enable) - return; - - /* 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 < CCDC_CSC_COEFF_TABLE_SIZE; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - /* - * convert decimal part to binary. Use 2 decimal - * precision, user values range from .00 - 0.99 - */ - val1 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - } else { - - /* CSCM - MSB */ - val2 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - val2 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - val2 <<= CCDC_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } -} - -/* - * ccdc_config_color_patterns() - * configure parameters for color patterns - */ -static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, - struct ccdc_col_pat *pat1) -{ - u32 val; - - val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | - (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | - (pat1->elop << 12) | (pat1->elep << 14)); - regw(val, COLPTN); -} - -/* This function will configure CCDC for Raw mode image capture */ -static int ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* restore power on defaults to register */ - ccdc_restore_defaults(); - - /* CCDCFG register: - * set CCD Not to swap input since input is RAW data - * set FID detection function to Latch at V-Sync - * set WENLOG - ccdc valid area to AND - * set TRGSEL to WENBIT - * set EXTRG to DISABLE - * disable latching function on VSYNC - shadowed registers - */ - regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | - CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | - CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); - - /* - * Set VDHD direction to input, input type to raw input - * normal data polarity, do not use external WEN - */ - val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | - CCDC_EXWEN_DISABLE); - - /* - * Configure the vertical sync polarity (MODESET.VDPOL), horizontal - * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), - * frame format(progressive or interlace), & pixel format (Input mode) - */ - val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); - - /* set pack for alaw compression */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - val |= CCDC_DATA_PACK_ENABLE; - - /* Configure for LPF */ - if (config_params->lpf_enable) - val |= (config_params->lpf_enable & CCDC_LPF_MASK) << - CCDC_LPF_SHIFT; - - /* Configure the data shift */ - val |= (config_params->datasft & CCDC_DATASFT_MASK) << - CCDC_DATASFT_SHIFT; - regw(val , MODESET); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); - - /* Configure the Median Filter threshold */ - regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); - - /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ - val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | - CCDC_CFA_MOSAIC; - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val |= (CCDC_ALAW_ENABLE | - ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) << - CCDC_GAMMAWD_INPUT_SHIFT)); - } - - /* Configure Median filter1 & filter2 */ - val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | - (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); - - regw(val, GAMMAWD); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 1); - - /* Optical Clamp Averaging */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* Vertical Defect Correction if needed */ - if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) - return -EFAULT; - - /* color space conversion */ - ccdc_config_csc(&config_params->csc); - - /* color pattern */ - ccdc_config_color_patterns(&config_params->col_pat_field0, - &config_params->col_pat_field1); - - /* Configure the Gain & offset control */ - ccdc_config_gain_offset(); - - dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); - - /* Configure DATAOFST register */ - val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_H_SHIFT; - val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_V_SHIFT; - regw(val, DATAOFST); - - /* configuring HSIZE register */ - 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 ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) { - val |= (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - /* adjust to multiple of 32 */ - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } else { - /* else one pixel will take 2 byte */ - val |= (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For interlace inverse mode */ - regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_INVERSE); - } else { - /* For interlace non inverse mode */ - regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_NORMAL); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_enable) { - /* For progessive inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_INVERSE); - } else { - /* For progessive non inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_NORMAL); - } - } - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - return 0; -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - alaw->enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(MODESET) >> 15) & 1; -} - -/* 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_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM355 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .enable = ccdc_enable, - .enable_out_to_sdram = ccdc_enable_output_to_sdram, - .set_hw_if_params = ccdc_set_hw_if_params, - .set_params = ccdc_set_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = 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, - }, -}; - -static int __init dm355_ccdc_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - /* Get and enable Master clock */ - ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(ccdc_cfg.mclk)) { - status = PTR_ERR(ccdc_cfg.mclk); - goto fail_nomap; - } - if (clk_enable(ccdc_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Get and enable Slave clock */ - ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); - if (IS_ERR(ccdc_cfg.sclk)) { - status = PTR_ERR(ccdc_cfg.sclk); - goto fail_mclk; - } - if (clk_enable(ccdc_cfg.sclk)) { - status = -ENODEV; - goto fail_sclk; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_sclk; - } - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_sclk: - clk_put(ccdc_cfg.sclk); -fail_mclk: - clk_put(ccdc_cfg.mclk); -fail_nomap: - iounmap(ccdc_cfg.base_addr); -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm355_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - clk_put(ccdc_cfg.mclk); - clk_put(ccdc_cfg.sclk); - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static struct platform_driver dm355_ccdc_driver = { - .driver = { - .name = "dm355_ccdc", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(dm355_ccdc_remove), - .probe = dm355_ccdc_probe, -}; - -static int __init dm355_ccdc_init(void) -{ - return platform_driver_register(&dm355_ccdc_driver); -} - -static void __exit dm355_ccdc_exit(void) -{ - platform_driver_unregister(&dm355_ccdc_driver); -} - -module_init(dm355_ccdc_init); -module_exit(dm355_ccdc_exit); diff --git a/drivers/media/video/davinci/dm355_ccdc_regs.h b/drivers/media/video/davinci/dm355_ccdc_regs.h deleted file mode 100644 index d6d2ef0..0000000 --- a/drivers/media/video/davinci/dm355_ccdc_regs.h +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 _DM355_CCDC_REGS_H -#define _DM355_CCDC_REGS_H - -/**************************************************************************\ -* 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 CCDC_REG_LAST DATAOFST -/************************************************************** -* Define for various register bit mask and shifts for CCDC -* -**************************************************************/ -#define CCDC_RAW_IP_MODE 0 -#define CCDC_VDHDOUT_INPUT 0 -#define CCDC_YCINSWP_RAW (0 << 4) -#define CCDC_EXWEN_DISABLE 0 -#define CCDC_DATAPOL_NORMAL 0 -#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 -#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) -#define CCDC_CCDCFG_WENLOG_AND 0 -#define CCDC_CCDCFG_TRGSEL_WEN 0 -#define CCDC_CCDCFG_EXTRG_DISABLE 0 -#define CCDC_CFA_MOSAIC 0 -#define CCDC_Y8POS_SHIFT 11 - -#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 1 -#define CCDC_GAMMAWD_CFA_SHIFT 5 -#define CCDC_GAMMAWD_INPUT_SHIFT 2 -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_VD_POL_NEGATIVE (1 << 2) -#define CCDC_FRM_FMT_MASK 1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_VDHDOUT_MASK 1 -#define CCDC_VDHDOUT_SHIFT 0 -#define CCDC_EXWEN_MASK 1 -#define CCDC_EXWEN_SHIFT 5 -#define CCDC_INPUT_MODE_MASK 3 -#define CCDC_INPUT_MODE_SHIFT 12 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_DATAPOL_MASK 1 -#define CCDC_DATAPOL_SHIFT 6 -#define CCDC_WEN_ENABLE (1 << 1) -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE 1 -#define CCDC_ALAW_GAMA_WD_MASK 7 -#define CCDC_REC656IF_BT656_EN 3 - -#define CCDC_FMTCFG_FMTMODE_MASK 3 -#define CCDC_FMTCFG_FMTMODE_SHIFT 1 -#define CCDC_FMTCFG_LNUM_MASK 3 -#define CCDC_FMTCFG_LNUM_SHIFT 4 -#define CCDC_FMTCFG_ADDRINC_MASK 7 -#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 1 -#define CCDC_HSIZE_VAL_MASK 0xFFF -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D -#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D -#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 -#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 -#define CCDC_START_PX_HOR_MASK 0x7FFF -#define CCDC_NUM_PX_HOR_MASK 0x7FFF -#define CCDC_START_VER_ONE_MASK 0x7FFF -#define CCDC_START_VER_TWO_MASK 0x7FFF -#define CCDC_NUM_LINES_VER 0x7FFF - -#define CCDC_BLK_CLAMP_ENABLE (1 << 15) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x1FFF -#define CCDC_BLK_SAMPLE_LN_MASK 3 -#define CCDC_BLK_SAMPLE_LN_SHIFT 13 - -#define CCDC_NUM_LINE_CALC_MASK 3 -#define CCDC_NUM_LINE_CALC_SHIFT 14 - -#define CCDC_BLK_DC_SUB_MASK 0x3FFF -#define CCDC_BLK_COMP_MASK 0xFF -#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 (1 << 15) -#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) -#define CCDC_FPC_ENABLE (1 << 15) -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 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 0xF - -#define CCDC_CSC_COEF_INTEG_MASK 7 -#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f -#define CCDC_CSC_COEF_INTEG_SHIFT 5 -#define CCDC_CSCM_MSB_SHIFT 8 -#define CCDC_CSC_ENABLE 1 -#define CCDC_CSC_DEC_MAX 32 - -#define CCDC_MFILT1_SHIFT 10 -#define CCDC_MFILT2_SHIFT 8 -#define CCDC_MED_FILT_THRESH 0x3FFF -#define CCDC_LPF_MASK 1 -#define CCDC_LPF_SHIFT 14 -#define CCDC_OFFSET_MASK 0x3FF -#define CCDC_DATASFT_MASK 7 -#define CCDC_DATASFT_SHIFT 8 - -#define CCDC_DF_ENABLE 1 - -#define CCDC_FMTPLEN_P0_MASK 0xF -#define CCDC_FMTPLEN_P1_MASK 0xF -#define CCDC_FMTPLEN_P2_MASK 7 -#define CCDC_FMTPLEN_P3_MASK 7 -#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 0x1FFF -#define CCDC_FMTLNH_MASK 0x1FFF -#define CCDC_FMTSLV_MASK 0x1FFF -#define CCDC_FMTLNV_MASK 0x7FFF -#define CCDC_FMTRLEN_MASK 0x1FFF -#define CCDC_FMTHCNT_MASK 0x1FFF - -#define CCDC_ADP_INIT_MASK 0x1FFF -#define CCDC_ADP_LINE_SHIFT 13 -#define CCDC_ADP_LINE_MASK 3 -#define CCDC_FMTPGN_APTR_MASK 7 - -#define CCDC_DFCCTL_GDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) -#define CCDC_DFCCTL_VDFCEN_SHIFT 4 -#define CCDC_DFCCTL_VDFCSL_MASK 3 -#define CCDC_DFCCTL_VDFCSL_SHIFT 5 -#define CCDC_DFCCTL_VDFCUDA_MASK 1 -#define CCDC_DFCCTL_VDFCUDA_SHIFT 7 -#define CCDC_DFCCTL_VDFLSFT_MASK 3 -#define CCDC_DFCCTL_VDFLSFT_SHIFT 8 -#define CCDC_DFCMEMCTL_DFCMARST_MASK 1 -#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 -#define CCDC_DFCMEMCTL_DFCMWR_MASK 1 -#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 -#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) - -#define CCDC_LSCCFG_GFTSF_MASK 7 -#define CCDC_LSCCFG_GFTSF_SHIFT 1 -#define CCDC_LSCCFG_GFTINV_MASK 0xf -#define CCDC_LSCCFG_GFTINV_SHIFT 4 -#define CCDC_LSC_GFTABLE_SEL_MASK 3 -#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 3 -#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 3 -#define CCDC_LSC_FRAC_MASK 0x3FFF -#define CCDC_LSC_CENTRE_MASK 0x3FFF -#define CCDC_LSC_COEF_MASK 0xff -#define CCDC_LSC_COEFL_SHIFT 0 -#define CCDC_LSC_COEFU_SHIFT 8 -#define CCDC_GAIN_MASK 0x7FF -#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) -#define CCDC_SYNCEN_WEN_MASK (1 << 1) -#define CCDC_SYNCEN_WEN_SHIFT 1 - -/* Power on Defaults in hardware */ -#define MODESET_DEFAULT 0x200 -#define CULH_DEFAULT 0xFFFF -#define CULV_DEFAULT 0xFF -#define GAIN_DEFAULT 256 -#define OUTCLIP_DEFAULT 0x3FFF -#define LSCCFG2_DEFAULT 0xE - -#endif diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c deleted file mode 100644 index af92764..0000000 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ /dev/null @@ -1,1090 +0,0 @@ -/* - * 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 - * - * CCDC hardware module for DM6446 - * ------------------------------ - * - * This module is for configuring CCD controller of DM6446 VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This - * module also allows application to configure individual - * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. - * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header - * files. The setparams() API is called by vpfe_capture driver - * to configure module parameters. This file is named DM644x so that other - * variants such DM6443 may be supported using the same module. - * - * TODO: Test Raw bayer parameter settings and bayer capture - * Split module parameter structure to module specific ioctl structs - * investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "dm644x_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM6446"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* Master clock */ - struct clk *mclk; - /* slave clock */ - struct clk *sclk; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .config_params = { - .data_sz = CCDC_DATA_10BITS, - }, - }, - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = CCDC_WIN_PAL, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - -#define CCDC_MAX_RAW_YUV_FORMATS 2 - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* CCDC Save/Restore context */ -static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int flag) -{ - regw(flag, CCDC_PCR); -} - -static void ccdc_enable_vport(int flag) -{ - if (flag) - /* enable video port */ - regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); - else - regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); -} - -/* - * ccdc_setwin() - * This function will configure the window size - * to be capture in CCDC reg - */ -void ccdc_setwin(struct v4l2_rect *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(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - 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, - CCDC_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, CCDC_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, CCDC_VDINT); - - } - regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, - CCDC_VERT_START); - regw(vert_nr_lines, CCDC_VERT_LINES); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -static void ccdc_readregs(void) -{ - unsigned int val = 0; - - val = regr(CCDC_ALAW); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); - val = regr(CCDC_CLAMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); - val = regr(CCDC_DCSUB); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); - val = regr(CCDC_BLKCMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); - val = regr(CCDC_FPC_ADDR); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); - val = regr(CCDC_FPC); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); - val = regr(CCDC_FMTCFG); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); - val = regr(CCDC_COLPTN); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); - val = regr(CCDC_FMT_HORZ); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); - val = regr(CCDC_FMT_VERT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); - val = regr(CCDC_HSIZE_OFF); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); - val = regr(CCDC_SDOFST); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); - val = regr(CCDC_VP_OUT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); - val = regr(CCDC_SYN_MODE); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); - val = regr(CCDC_HORZ_INFO); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); - val = regr(CCDC_VERT_START); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); - val = regr(CCDC_VERT_LINES); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); -} - -static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) -{ - if (ccdcparam->alaw.enable) { - if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || - (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || - (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { - dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); - return -1; - } - } - return 0; -} - -static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int *fpc_virtaddr = NULL; - unsigned int *fpc_physaddr = NULL; - - memcpy(config_params, raw_params, sizeof(*raw_params)); - /* - * allocate memory for fault pixel table and copy the user - * values to the table - */ - if (!config_params->fault_pxl.enable) - return 0; - - fpc_physaddr = (unsigned int *)config_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 != config_params->fault_pxl.fp_num) { - if (fpc_physaddr != NULL) { - free_pages((unsigned long)fpc_physaddr, - get_order - (config_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_dbg(ccdc_cfg.dev, - "\nUnable to allocate memory for FPC"); - return -EFAULT; - } - fpc_physaddr = - (unsigned int *)virt_to_phys((void *)fpc_virtaddr); - } - - /* Copy number of fault pixels and FPC table */ - config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; - if (copy_from_user(fpc_virtaddr, - (void __user *)raw_params->fault_pxl.fpc_table_addr, - config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { - dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); - return -EFAULT; - } - config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; - return 0; -} - -static int ccdc_close(struct device *dev) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; - - fpc_physaddr = (unsigned int *)config_params->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(config_params->fault_pxl.fp_num * - FP_NUM_BYTES)); - } - return 0; -} - -/* - * ccdc_restore_defaults() - * This function will write defaults to all CCDC registers - */ -static void ccdc_restore_defaults(void) -{ - int i; - - /* disable CCDC */ - ccdc_enable(0); - /* set all registers to default value */ - for (i = 4; i <= 0x94; i += 4) - regw(0, i); - regw(CCDC_NO_CULLING, CCDC_CULLING); - regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); -} - -static int ccdc_open(struct device *device) -{ - ccdc_restore_defaults(); - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_enable_vport(1); - return 0; -} - -static void ccdc_sbl_reset(void) -{ - vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); -} - -/* Parameter operations */ -static int ccdc_set_params(void __user *params) -{ - struct ccdc_config_params_raw ccdc_raw_params; - int x; - - if (ccdc_cfg.if_type != VPFE_RAW_BAYER) - return -EINVAL; - - x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); - if (x) { - dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" - "ccdc params, %d\n", x); - return -EFAULT; - } - - if (!validate_ccdc_param(&ccdc_raw_params)) { - if (!ccdc_update_raw_params(&ccdc_raw_params)) - return 0; - } - return -EINVAL; -} - -/* - * ccdc_config_ycbcr() - * This function will configure CCDC for YCbCr video capture - */ -void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 syn_mode; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - /* - * first restore the CCDC registers to default values - * This is important since we assume default values to be set in - * a lot of registers that we didn't touch - */ - ccdc_restore_defaults(); - - /* - * configure pixel format, frame format, configure video frame - * format, enable output to SDRAM, enable internal timing generator - * and 8bit pack mode - */ - syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << - CCDC_SYN_MODE_INPMOD_SHIFT) | - ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << - CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | - CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); - - /* - * configure the FID, VD, HD pin polarity, - * fld,hd pol positive, vd negative, 8-bit data - */ - syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - syn_mode |= CCDC_SYN_MODE_10BITS; - else - syn_mode |= CCDC_SYN_MODE_8BITS; - } else { - /* y/c external sync mode */ - syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - regw(syn_mode, CCDC_SYN_MODE); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the order of y cb cr in SDRAM, and disable latch - * internal register on vsync - */ - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, - CCDC_CCDCFG); - else - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * configure the horizontal line offset. This should be a - * on 32 byte bondary. So clear LSB 5 bits - */ - regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->enable) { - /* configure DCSub */ - val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; - regw(val, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); - regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); - return; - } - /* - * Configure gain, Start pixel, No of line to be avg, - * No of pixel/line to be avg, & Enable the Black clamping - */ - val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | - ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << - CCDC_BLK_ST_PXL_SHIFT) | - ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << - CCDC_BLK_SAMPLE_LINE_SHIFT) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); - regw(val, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); - /* If Black clamping is enable then make dcsub 0 */ - regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); -} - -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = ((bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT) | - ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT)); - regw(val, CCDC_BLKCMP); -} - -static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) -{ - u32 val; - - /* Initially disable FPC */ - val = CCDC_FPC_DISABLE; - regw(val, CCDC_FPC); - - if (!fpc->enable) - return; - - /* Configure Fault pixel if needed */ - regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", - (fpc->fpc_table_addr)); - /* Write the FPC params with FPC disable */ - val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; - regw(val, CCDC_FPC); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); - /* read the FPC register */ - val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; - regw(val, CCDC_FPC); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); -} - -/* - * ccdc_config_raw() - * This function will configure CCDC for Raw capture mode - */ -void ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int syn_mode = 0; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* Reset CCDC */ - ccdc_restore_defaults(); - - /* Disable latching function registers on VSYNC */ - regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * Configure the vertical sync polarity(SYN_MODE.VDPOL), - * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity - * (SYN_MODE.FLDPOL), frame format(progressive or interlace), - * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output - * SDRAM, enable internal timing generator - */ - syn_mode = - (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((config_params->data_sz & CCDC_DATA_SZ_MASK) << - CCDC_DATA_SZ_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | - CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val = ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); - regw(val, CCDC_ALAW); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); - } - - /* Configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); - - /* Configure Black Clamp */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Configure Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* Configure Fault Pixel Correction */ - ccdc_config_fpc(&config_params->fault_pxl); - - /* If data size is 8 bit then pack the data */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - syn_mode |= CCDC_DATA_PACK_ENABLE; - -#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE - /* enable video port */ - val = CCDC_ENABLE_VIDEO_PORT; -#else - /* disable video port */ - val = CCDC_DISABLE_VIDEO_PORT; -#endif - - if (config_params->data_sz == CCDC_DATA_8BITS) - val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - else - val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - /* Write value in FMTCFG */ - regw(val, CCDC_FMTCFG); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); - /* Configure the color pattern according to mt9t001 sensor */ - regw(CCDC_COLPTN_VAL, CCDC_COLPTN); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); - /* - * Configure Data formatter(Video port) pixel selection - * (FMT_HORZ, FMT_VERT) - */ - val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << - CCDC_FMT_HORZ_FMTSPH_SHIFT) | - (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); - regw(val, CCDC_FMT_HORZ); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); - 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(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", - params->win.height); - regw(val, CCDC_FMT_VERT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); - - dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); - - /* - * Configure Horizontal offset register. If pack 8 is enabled then - * 1 pixel will take 1 byte - */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & - CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); - else - /* else one pixel will take 2 byte */ - regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + - CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, - CCDC_HSIZE_OFF); - - /* Set value for SDOFST */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For intelace inverse mode */ - regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); - } - - else { - /* For intelace non inverse mode */ - regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.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, CCDC_VP_OUT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); - regw(syn_mode, CCDC_SYN_MODE); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - ccdc_readregs(); -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} - -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - ccdc_cfg.bayer.config_params.alaw.enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} - -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(CCDC_SYN_MODE) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw(addr & 0xffffffe0, CCDC_SDR_ADDR); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - case VPFE_BT656_10BIT: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static void ccdc_save_context(void) -{ - ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); - ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); - ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); - ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); - ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); - ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); - ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); - ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); - ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); - ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); - ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); - ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); - ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); - ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); - ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); - ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); - ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); - ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); - ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); - ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); - ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); - ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); - ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); - ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); - ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); - ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); - ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); - ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); - ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); - ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); - ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); - ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); - ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); - ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); - ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); - ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); - ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); -} - -static void ccdc_restore_context(void) -{ - regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); - regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); - regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); - regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); - regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); - regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); - regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); - regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); - regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); - regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); - regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); - regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); - regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); - regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); - regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); - regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); - regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); - regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); - regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); - regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); - regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); - regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); - regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); - regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); - regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); - regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); - regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); - regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); - regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); - regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); - regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); - regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); - regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); - regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); - regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); - regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); - regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); -} -static struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM6446 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .reset = ccdc_sbl_reset, - .enable = ccdc_enable, - .set_hw_if_params = ccdc_set_hw_if_params, - .set_params = ccdc_set_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = 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, - }, -}; - -static int __init dm644x_ccdc_probe(struct platform_device *pdev) -{ - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - /* Get and enable Master clock */ - ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(ccdc_cfg.mclk)) { - status = PTR_ERR(ccdc_cfg.mclk); - goto fail_nomap; - } - if (clk_enable(ccdc_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Get and enable Slave clock */ - ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); - if (IS_ERR(ccdc_cfg.sclk)) { - status = PTR_ERR(ccdc_cfg.sclk); - goto fail_mclk; - } - if (clk_enable(ccdc_cfg.sclk)) { - status = -ENODEV; - goto fail_sclk; - } - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_sclk: - clk_put(ccdc_cfg.sclk); -fail_mclk: - clk_put(ccdc_cfg.mclk); -fail_nomap: - iounmap(ccdc_cfg.base_addr); -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm644x_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - clk_put(ccdc_cfg.mclk); - clk_put(ccdc_cfg.sclk); - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static int dm644x_ccdc_suspend(struct device *dev) -{ - /* Save CCDC context */ - ccdc_save_context(); - /* Disable CCDC */ - ccdc_enable(0); - /* Disable both master and slave clock */ - clk_disable(ccdc_cfg.mclk); - clk_disable(ccdc_cfg.sclk); - - return 0; -} - -static int dm644x_ccdc_resume(struct device *dev) -{ - /* Enable both master and slave clock */ - clk_enable(ccdc_cfg.mclk); - clk_enable(ccdc_cfg.sclk); - /* Restore CCDC context */ - ccdc_restore_context(); - - return 0; -} - -static const struct dev_pm_ops dm644x_ccdc_pm_ops = { - .suspend = dm644x_ccdc_suspend, - .resume = dm644x_ccdc_resume, -}; - -static struct platform_driver dm644x_ccdc_driver = { - .driver = { - .name = "dm644x_ccdc", - .owner = THIS_MODULE, - .pm = &dm644x_ccdc_pm_ops, - }, - .remove = __devexit_p(dm644x_ccdc_remove), - .probe = dm644x_ccdc_probe, -}; - -static int __init dm644x_ccdc_init(void) -{ - return platform_driver_register(&dm644x_ccdc_driver); -} - -static void __exit dm644x_ccdc_exit(void) -{ - platform_driver_unregister(&dm644x_ccdc_driver); -} - -module_init(dm644x_ccdc_init); -module_exit(dm644x_ccdc_exit); diff --git a/drivers/media/video/davinci/dm644x_ccdc_regs.h b/drivers/media/video/davinci/dm644x_ccdc_regs.h deleted file mode 100644 index 90370e4..0000000 --- a/drivers/media/video/davinci/dm644x_ccdc_regs.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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 _DM644X_CCDC_REGS_H -#define _DM644X_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define CCDC_PID 0x0 -#define CCDC_PCR 0x4 -#define CCDC_SYN_MODE 0x8 -#define CCDC_HD_VD_WID 0xc -#define CCDC_PIX_LINES 0x10 -#define CCDC_HORZ_INFO 0x14 -#define CCDC_VERT_START 0x18 -#define CCDC_VERT_LINES 0x1c -#define CCDC_CULLING 0x20 -#define CCDC_HSIZE_OFF 0x24 -#define CCDC_SDOFST 0x28 -#define CCDC_SDR_ADDR 0x2c -#define CCDC_CLAMP 0x30 -#define CCDC_DCSUB 0x34 -#define CCDC_COLPTN 0x38 -#define CCDC_BLKCMP 0x3c -#define CCDC_FPC 0x40 -#define CCDC_FPC_ADDR 0x44 -#define CCDC_VDINT 0x48 -#define CCDC_ALAW 0x4c -#define CCDC_REC656IF 0x50 -#define CCDC_CCDCFG 0x54 -#define CCDC_FMTCFG 0x58 -#define CCDC_FMT_HORZ 0x5c -#define CCDC_FMT_VERT 0x60 -#define CCDC_FMT_ADDR0 0x64 -#define CCDC_FMT_ADDR1 0x68 -#define CCDC_FMT_ADDR2 0x6c -#define CCDC_FMT_ADDR3 0x70 -#define CCDC_FMT_ADDR4 0x74 -#define CCDC_FMT_ADDR5 0x78 -#define CCDC_FMT_ADDR6 0x7c -#define CCDC_FMT_ADDR7 0x80 -#define CCDC_PRGEVEN_0 0x84 -#define CCDC_PRGEVEN_1 0x88 -#define CCDC_PRGODD_0 0x8c -#define CCDC_PRGODD_1 0x90 -#define CCDC_VP_OUT 0x94 -#define CCDC_REG_END 0x98 - -/*************************************************************** -* Define for various register bit mask and shifts for CCDC -****************************************************************/ -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_HSIZE_OFF_MASK 0xffffffe0 -#define CCDC_32BYTE_ALIGN_VAL 31 -#define CCDC_FRM_FMT_MASK 0x1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF -#define CCDC_WEN_ENABLE (1 << 17) -#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE (1 << 3) -#define CCDC_ALAW_GAMA_WD_MASK 7 -#define CCDC_BLK_CLAMP_ENABLE (1 << 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 7 -#define CCDC_BLK_SAMPLE_LN_SHIFT 28 -#define CCDC_BLK_SAMPLE_LINE_MASK 7 -#define CCDC_BLK_SAMPLE_LINE_SHIFT 25 -#define CCDC_BLK_DC_SUB_MASK 0x03FFF -#define CCDC_BLK_COMP_MASK 0xFF -#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 (1 << 15) -#define CCDC_FPC_ENABLE (1 << 15) -#define CCDC_FPC_DISABLE 0 -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) -#define CCDC_FMTCFG_VPIN_MASK 7 -#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 0xF -#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 -#define CCDC_PPC_RAW 1 -#define CCDC_DCSUB_DEFAULT_VAL 0 -#define CCDC_CLAMP_DEFAULT_VAL 0 -#define CCDC_ENABLE_VIDEO_PORT 0x8000 -#define CCDC_DISABLE_VIDEO_PORT 0 -#define CCDC_COLPTN_VAL 0xBB11BB11 -#define CCDC_TWO_BYTES_PER_PIXEL 2 -#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D -#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 -#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 -#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 -#define CCDC_INTERLACED_HEIGHT_SHIFT 1 -#define CCDC_SYN_MODE_INPMOD_SHIFT 12 -#define CCDC_SYN_MODE_INPMOD_MASK 3 -#define CCDC_SYN_MODE_8BITS (7 << 8) -#define CCDC_SYN_MODE_10BITS (6 << 8) -#define CCDC_SYN_MODE_11BITS (5 << 8) -#define CCDC_SYN_MODE_12BITS (4 << 8) -#define CCDC_SYN_MODE_13BITS (3 << 8) -#define CCDC_SYN_MODE_14BITS (2 << 8) -#define CCDC_SYN_MODE_15BITS (1 << 8) -#define CCDC_SYN_MODE_16BITS (0 << 8) -#define CCDC_SYN_FLDMODE_MASK 1 -#define CCDC_SYN_FLDMODE_SHIFT 7 -#define CCDC_REC656IF_BT656_EN 3 -#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) -#define CCDC_CCDCFG_Y8POS_SHIFT 11 -#define CCDC_CCDCFG_BW656_10BIT (1 << 5) -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_NO_CULLING 0xffff00ff -#endif diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c deleted file mode 100644 index 29c29c6..0000000 --- a/drivers/media/video/davinci/isif.c +++ /dev/null @@ -1,1172 +0,0 @@ -/* - * 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 - * - * Image Sensor Interface (ISIF) driver - * - * This driver is for configuring the ISIF IP available on DM365 or any other - * TI SoCs. This is used for capturing yuv or bayer video or image data - * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 - * and DM6446, but with enhanced or additional ip blocks. The driver - * configures the ISIF upon commands from the vpfe bridge driver through - * ccdc_hw_device interface. - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Add support for control ioctl - */ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "isif_regs.h" -#include "ccdc_hw_device.h" - -/* Defaults for module configuration parameters */ -static struct isif_config_params_raw isif_config_defaults = { - .linearize = { - .en = 0, - .corr_shft = ISIF_NO_SHIFT, - .scale_fact = {1, 0}, - }, - .df_csc = { - .df_or_csc = 0, - .csc = { - .en = 0, - }, - }, - .dfc = { - .en = 0, - }, - .bclamp = { - .en = 0, - }, - .gain_offset = { - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - }, - .culling = { - .hcpat_odd = 0xff, - .hcpat_even = 0xff, - .vcpat = 0xff, - }, - .compress = { - .alg = ISIF_ALAW, - }, -}; - -/* ISIF operation configuration */ -static struct isif_oper_config { - struct device *dev; - enum vpfe_hw_if_type if_type; - struct isif_ycbcr_config ycbcr; - struct isif_params_raw bayer; - enum isif_data_pack data_pack; - /* Master clock */ - struct clk *mclk; - /* ISIF base address */ - void __iomem *base_addr; - /* ISIF Linear Table 0 */ - void __iomem *linear_tbl0_addr; - /* ISIF Linear Table 1 */ - void __iomem *linear_tbl1_addr; -} isif_cfg = { - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = ISIF_WIN_NTSC, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, - }, - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = ISIF_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - .cfa_pat = ISIF_CFA_PAT_MOSAIC, - .data_msb = ISIF_BIT_MSB_11, - .config_params = { - .data_shift = ISIF_NO_SHIFT, - .col_pat_field0 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .col_pat_field1 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .test_pat_gen = 0, - }, - }, - .data_pack = ISIF_DATA_PACK8, -}; - -/* Raw Bayer formats */ -static const u32 isif_raw_bayer_pix_formats[] = { - V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static const u32 isif_raw_yuv_pix_formats[] = { - V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(isif_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, isif_cfg.base_addr + offset); -} - -/* reg_modify() - read, modify and write register */ -static inline u32 reg_modify(u32 mask, u32 val, u32 offset) -{ - u32 new_val = (regr(offset) & ~mask) | (val & mask); - - regw(new_val, offset); - return new_val; -} - -static inline void regw_lin_tbl(u32 val, u32 offset, int i) -{ - if (!i) - __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); - else - __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); -} - -static void isif_disable_all_modules(void) -{ - /* disable BC */ - regw(0, CLAMPCFG); - /* disable vdfc */ - regw(0, DFCCTL); - /* disable CSC */ - regw(0, CSCCTL); - /* disable linearization */ - regw(0, LINCFG0); - /* disable other modules here as they are supported */ -} - -static void isif_enable(int en) -{ - if (!en) { - /* Before disable isif, disable all ISIF modules */ - isif_disable_all_modules(); - /* - * wait for next VD. Assume lowest scan rate is 12 Hz. So - * 100 msec delay is good enough - */ - msleep(100); - } - reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); -} - -static void isif_enable_output_to_sdram(int en) -{ - reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); -} - -static void isif_config_culling(struct isif_cul *cul) -{ - u32 val; - - /* Horizontal pattern */ - val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; - regw(val, CULH); - - /* vertical pattern */ - regw(cul->vcpat, CULV); - - /* LPF */ - reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, - cul->en_lpf << ISIF_LPF_SHIFT, MODESET); -} - -static void isif_config_gain_offset(void) -{ - struct isif_gain_offsets_adj *gain_off_p = - &isif_cfg.bayer.config_params.gain_offset; - u32 val; - - val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | - (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | - (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | - (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | - (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | - (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); - - reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); - - val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.r_ye.decimal; - regw(val, CRGAIN); - - val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gr_cy.decimal; - regw(val, CGRGAIN); - - val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gb_g.decimal; - regw(val, CGBGAIN); - - val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.b_mg.decimal; - regw(val, CBGAIN); - - regw(gain_off_p->offset, COFSTA); -} - -static void isif_restore_defaults(void) -{ - enum vpss_ccdc_source_sel source = VPSS_CCDCIN; - - dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); - isif_cfg.bayer.config_params = isif_config_defaults; - /* Enable clock to ISIF, IPIPEIF and BL */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 1); - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - vpss_enable_clock(VPSS_BL_CLOCK, 1); - /* Set default offset and gain */ - isif_config_gain_offset(); - vpss_select_ccdc_source(source); - dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); -} - -static int isif_open(struct device *device) -{ - isif_restore_defaults(); - return 0; -} - -/* This function will configure the window size to be capture in ISIF reg */ -static void isif_setwin(struct v4l2_rect *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(isif_cfg.dev, "\nStarting isif_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - 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, LNH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - } else { - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(mid_img, VDINT1); - } - - regw(0, VDINT0); - regw(vert_start & START_VER_ONE_MASK, SLV0); - regw(vert_start & START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & NUM_LINES_VER, LNV); -} - -static void isif_config_bclamp(struct isif_black_clamp *bc) -{ - u32 val; - - /* - * DC Offset is always added to image data irrespective of bc enable - * status - */ - regw(bc->dc_offset, CLDCOFST); - - if (bc->en) { - val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; - - /* Enable BC and horizontal clamp caculation paramaters */ - val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); - - regw(val, CLAMPCFG); - - if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { - /* - * Window count for calculation - * Base window selection - * pixel limit - * Horizontal size of window - * vertical size of the window - * Horizontal start position of the window - * Vertical start position of the window - */ - val = bc->horz.win_count_calc | - ((!!bc->horz.base_win_sel_calc) << - ISIF_HORZ_BC_WIN_SEL_SHIFT) | - ((!!bc->horz.clamp_pix_limit) << - ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | - (bc->horz.win_h_sz_calc << - ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | - (bc->horz.win_v_sz_calc << - ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); - regw(val, CLHWIN0); - - regw(bc->horz.win_start_h_calc, CLHWIN1); - regw(bc->horz.win_start_v_calc, CLHWIN2); - } - - /* vertical clamp caculation paramaters */ - - /* Reset clamp value sel for previous line */ - val |= - (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | - (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); - regw(val, CLVWIN0); - - /* Optical Black horizontal start position */ - regw(bc->vert.ob_start_h, CLVWIN1); - /* Optical Black vertical start position */ - regw(bc->vert.ob_start_v, CLVWIN2); - /* Optical Black vertical size for calculation */ - regw(bc->vert.ob_v_sz_calc, CLVWIN3); - /* Vertical start position for BC subtraction */ - regw(bc->vert_start_sub, CLSV); - } -} - -static void isif_config_linearization(struct isif_linearize *linearize) -{ - u32 val, i; - - if (!linearize->en) { - regw(0, LINCFG0); - return; - } - - /* shift value for correction & enable linearization (set lsb) */ - val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; - regw(val, LINCFG0); - - /* Scale factor */ - val = ((!!linearize->scale_fact.integer) << - ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | - linearize->scale_fact.decimal; - regw(val, LINCFG1); - - for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { - if (i % 2) - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); - else - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); - } -} - -static int isif_config_dfc(struct isif_dfc *vdfc) -{ - /* initialize retries to loop for max ~ 250 usec */ - u32 val, count, retries = loops_per_jiffy / (4000/HZ); - int i; - - if (!vdfc->en) - return 0; - - /* Correction mode */ - val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); - - /* Correct whole line or partial */ - if (vdfc->corr_whole_line) - val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; - - /* level shift value */ - val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; - - regw(val, DFCCTL); - - /* Defect saturation level */ - regw(vdfc->def_sat_level, VDFSATLV); - - regw(vdfc->table[0].pos_vert, DFCMEM0); - regw(vdfc->table[0].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[0].level_at_pos, DFCMEM2); - regw(vdfc->table[0].level_up_pixels, DFCMEM3); - regw(vdfc->table[0].level_low_pixels, DFCMEM4); - } - - /* set DFCMARST and set DFCMWR */ - val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - - for (i = 1; i < vdfc->num_vdefects; i++) { - regw(vdfc->table[i].pos_vert, DFCMEM0); - regw(vdfc->table[i].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[i].level_at_pos, DFCMEM2); - regw(vdfc->table[i].level_up_pixels, DFCMEM3); - regw(vdfc->table[i].level_low_pixels, DFCMEM4); - } - val = regr(DFCMEMCTL); - /* clear DFCMARST and set DFCMWR */ - val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_err(isif_cfg.dev, - "defect table write timeout !!!\n"); - return -1; - } - } - if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { - /* Extra cycle needed */ - regw(0, DFCMEM0); - regw(0x1FFF, DFCMEM1); - regw(1, DFCMEMCTL); - } - - /* enable VDFC */ - reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), - DFCCTL); - return 0; -} - -static void isif_config_csc(struct isif_df_csc *df_csc) -{ - u32 val1 = 0, val2 = 0, i; - - if (!df_csc->csc.en) { - regw(0, CSCCTL); - return; - } - for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - } else { - - /* CSCM - MSB */ - val2 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - val2 <<= ISIF_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } - - /* program the active area */ - regw(df_csc->start_pix, FMTSPH); - /* - * one extra pixel as required for CSC. Actually number of - * pixel - 1 should be configured in this register. So we - * need to subtract 1 before writing to FMTSPH, but we will - * not do this since csc requires one extra pixel - */ - regw(df_csc->num_pixels, FMTLNH); - regw(df_csc->start_line, FMTSLV); - /* - * one extra line as required for CSC. See reason documented for - * num_pixels - */ - regw(df_csc->num_lines, FMTLNV); - - /* Enable CSC */ - regw(1, CSCCTL); -} - -static int isif_config_raw(void) -{ - struct isif_params_raw *params = &isif_cfg.bayer; - struct isif_config_params_raw *module_params = - &isif_cfg.bayer.config_params; - struct vpss_pg_frame_size frame_size; - struct vpss_sync_pol sync; - u32 val; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); - - /* - * Configure CCDCFG register:- - * Set CCD Not to swap input since input is RAW data - * Set FID detection function to Latch at V-Sync - * Set WENLOG - isif valid area - * Set TRGSEL - * Set EXTRG - * Packed to 8 or 16 bits - */ - - val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | - ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | - ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; - - dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); - regw(val, CCDCFG); - - /* - * Configure the vertical sync polarity(MODESET.VDPOL) - * Configure the horizontal sync polarity (MODESET.HDPOL) - * Configure frame id polarity (MODESET.FLDPOL) - * Configure data polarity - * Configure External WEN Selection - * Configure frame format(progressive or interlace) - * Configure pixel format (Input mode) - * Configure the data shift - */ - - val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | - (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->config_params.data_shift << ISIF_DATASFT_SHIFT); - - regw(val, MODESET); - dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); - - /* - * Configure GAMMAWD register - * CFA pattern setting - */ - val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; - - /* Gamma msb */ - if (module_params->compress.alg == ISIF_ALAW) - val |= ISIF_ALAW_ENABLE; - - val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); - regw(val, CGAMMAWD); - - /* Configure DPCM compression settings */ - if (module_params->compress.alg == ISIF_DPCM) { - val = BIT(ISIF_DPCM_EN_SHIFT) | - (module_params->compress.pred << - ISIF_DPCM_PREDICTOR_SHIFT); - } - - regw(val, MISC); - - /* Configure Gain & Offset */ - isif_config_gain_offset(); - - /* Configure Color pattern */ - val = (params->config_params.col_pat_field0.olop) | - (params->config_params.col_pat_field0.olep << 2) | - (params->config_params.col_pat_field0.elop << 4) | - (params->config_params.col_pat_field0.elep << 6) | - (params->config_params.col_pat_field1.olop << 8) | - (params->config_params.col_pat_field1.olep << 10) | - (params->config_params.col_pat_field1.elop << 12) | - (params->config_params.col_pat_field1.elep << 14); - regw(val, CCOLP); - dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); - - /* Configure HSIZE register */ - val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; - - /* calculate line offset in 32 bytes based on pack value */ - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - val |= ((params->win.width + 31) >> 5); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - val |= (((params->win.width + - (params->win.width >> 2)) + 31) >> 5); - else - val |= (((params->win.width * 2) + 31) >> 5); - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_en) { - /* For interlace inverse mode */ - regw(0x4B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); - } else { - /* For interlace non inverse mode */ - regw(0x0B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_en) { - /* For progressive inverse mode */ - regw(0x4000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); - } else { - /* For progressive non inverse mode */ - regw(0x0000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); - } - } - - /* Configure video window */ - isif_setwin(¶ms->win, params->frm_fmt, 1); - - /* Configure Black Clamp */ - isif_config_bclamp(&module_params->bclamp); - - /* Configure Vertical Defection Pixel Correction */ - if (isif_config_dfc(&module_params->dfc) < 0) - return -EFAULT; - - if (!module_params->df_csc.df_or_csc) - /* Configure Color Space Conversion */ - isif_config_csc(&module_params->df_csc); - - isif_config_linearization(&module_params->linearize); - - /* Configure Culling */ - isif_config_culling(&module_params->culling); - - /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ - regw(module_params->horz_offset, DATAHOFST); - regw(module_params->vert_offset, DATAVOFST); - - /* Setup test pattern if enabled */ - if (params->config_params.test_pat_gen) { - /* Use the HD/VD pol settings from user */ - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - frame_size.hlpfr = isif_cfg.bayer.win.width; - frame_size.pplen = isif_cfg.bayer.win.height; - dm365_vpss_set_pg_frame_size(frame_size); - vpss_select_ccdc_source(VPSS_PGLPBK); - } - - dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); - return 0; -} - -static int isif_set_buftype(enum ccdc_buftype buf_type) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.buf_type = buf_type; - else - isif_cfg.ycbcr.buf_type = buf_type; - - return 0; - -} -static enum ccdc_buftype isif_get_buftype(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.buf_type; - - return isif_cfg.ycbcr.buf_type; -} - -static int isif_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { - *pix = isif_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { - *pix = isif_raw_yuv_pix_formats[i]; - ret = 0; - } - } - - return ret; -} - -static int isif_set_pixel_format(unsigned int pixfmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (pixfmt == V4L2_PIX_FMT_SBGGR8) { - if ((isif_cfg.bayer.config_params.compress.alg != - ISIF_ALAW) && - (isif_cfg.bayer.config_params.compress.alg != - ISIF_DPCM)) { - dev_dbg(isif_cfg.dev, - "Either configure A-Law or DPCM\n"); - return -EINVAL; - } - isif_cfg.data_pack = ISIF_PACK_8BIT; - } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { - isif_cfg.bayer.config_params.compress.alg = - ISIF_NO_COMPRESSION; - isif_cfg.data_pack = ISIF_PACK_16BIT; - } else - return -EINVAL; - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - isif_cfg.data_pack = ISIF_PACK_8BIT; - } - return 0; -} - -static u32 isif_get_pixel_format(void) -{ - u32 pixfmt; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) - if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || - isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int isif_set_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - isif_cfg.bayer.win.top = win->top; - isif_cfg.bayer.win.left = win->left; - isif_cfg.bayer.win.width = win->width; - isif_cfg.bayer.win.height = win->height; - } else { - isif_cfg.ycbcr.win.top = win->top; - isif_cfg.ycbcr.win.left = win->left; - isif_cfg.ycbcr.win.width = win->width; - isif_cfg.ycbcr.win.height = win->height; - } - return 0; -} - -static void isif_get_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - *win = isif_cfg.bayer.win; - else - *win = isif_cfg.ycbcr.win; -} - -static unsigned int isif_get_line_length(void) -{ - unsigned int len; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - len = ((isif_cfg.bayer.win.width)); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - len = (((isif_cfg.bayer.win.width * 2) + - (isif_cfg.bayer.win.width >> 2))); - else - len = (((isif_cfg.bayer.win.width * 2))); - } else - len = (((isif_cfg.ycbcr.win.width * 2))); - return ALIGN(len, 32); -} - -static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.frm_fmt = frm_fmt; - else - isif_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} -static enum ccdc_frmfmt isif_get_frame_format(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.frm_fmt; - return isif_cfg.ycbcr.frm_fmt; -} - -static int isif_getfid(void) -{ - return (regr(MODESET) >> 15) & 0x1; -} - -/* misc operations */ -static void isif_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x07ff, CADU); - regw((addr >> 5) & 0x0ffff, CADL); -} - -static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - isif_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_BT656_10BIT: - case VPFE_YCBCR_SYNC_8: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_BT1120: - case VPFE_YCBCR_SYNC_16: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_RAW_BAYER: - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - break; - default: - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - return 0; -} - -/* This function will configure ISIF for YCbCr parameters. */ -static int isif_config_ycbcr(void) -{ - struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - struct vpss_pg_frame_size frame_size; - u32 modeset = 0, ccdcfg = 0; - struct vpss_sync_pol sync; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); - - /* configure pixel format or input mode */ - modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->vd_pol << ISIF_VD_POL_SHIFT); - - /* pack the data to 8-bit ISIFCFG */ - switch (isif_cfg.if_type) { - case VPFE_BT656: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); - regw(3, REC656IF); - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; - break; - case VPFE_BT656_10BIT: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* setup BT.656, embedded sync */ - regw(3, REC656IF); - /* enable 10 bit mode in ccdcfg */ - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | - ISIF_BW656_ENABLE; - break; - case VPFE_BT1120: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - regw(3, REC656IF); - break; - - case VPFE_YCBCR_SYNC_8: - ccdcfg |= ISIF_DATA_PACK8; - ccdcfg |= ISIF_YCINSWP_YCBCR; - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - case VPFE_YCBCR_SYNC_16: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - default: - /* should never come here */ - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - regw(modeset, MODESET); - - /* Set up pix order */ - ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; - - regw(ccdcfg, CCDCFG); - - /* configure video window */ - if ((isif_cfg.if_type == VPFE_BT1120) || - (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) - isif_setwin(¶ms->win, params->frm_fmt, 1); - else - isif_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * 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->frm_fmt == CCDC_FRMFMT_INTERLACED) && - (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) - /* two fields are interleaved in memory */ - regw(0x00000249, SDOFST); - - /* Setup test pattern if enabled */ - if (isif_cfg.bayer.config_params.test_pat_gen) { - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - dm365_vpss_set_pg_frame_size(frame_size); - } - return 0; -} - -static int isif_configure(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_config_raw(); - return isif_config_ycbcr(); -} - -static int isif_close(struct device *device) -{ - /* copy defaults to module params */ - isif_cfg.bayer.config_params = isif_config_defaults; - return 0; -} - -static struct ccdc_hw_device isif_hw_dev = { - .name = "ISIF", - .owner = THIS_MODULE, - .hw_ops = { - .open = isif_open, - .close = isif_close, - .enable = isif_enable, - .enable_out_to_sdram = isif_enable_output_to_sdram, - .set_hw_if_params = isif_set_hw_if_params, - .configure = isif_configure, - .set_buftype = isif_set_buftype, - .get_buftype = isif_get_buftype, - .enum_pix = isif_enum_pix, - .set_pixel_format = isif_set_pixel_format, - .get_pixel_format = isif_get_pixel_format, - .set_frame_format = isif_set_frame_format, - .get_frame_format = isif_get_frame_format, - .set_image_window = isif_set_image_window, - .get_image_window = isif_get_image_window, - .get_line_length = isif_get_line_length, - .setfbaddr = isif_setfbaddr, - .getfid = isif_getfid, - }, -}; - -static int __init isif_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - void *__iomem addr; - int status = 0, i; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&isif_hw_dev); - if (status < 0) - return status; - - /* Get and enable Master clock */ - isif_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(isif_cfg.mclk)) { - status = PTR_ERR(isif_cfg.mclk); - goto fail_mclk; - } - if (clk_enable(isif_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_mclk; - } - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - - i = 0; - /* Get the ISIF base address, linearization table0 and table1 addr. */ - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - status = -ENODEV; - goto fail_nobase_res; - } - res = request_mem_region(res->start, resource_size(res), - res->name); - if (!res) { - status = -EBUSY; - goto fail_nobase_res; - } - addr = ioremap_nocache(res->start, resource_size(res)); - if (!addr) { - status = -ENOMEM; - goto fail_base_iomap; - } - switch (i) { - case 0: - /* ISIF base address */ - isif_cfg.base_addr = addr; - break; - case 1: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl0_addr = addr; - break; - default: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl1_addr = addr; - break; - } - i++; - } - isif_cfg.dev = &pdev->dev; - - printk(KERN_NOTICE "%s is registered with vpfe.\n", - isif_hw_dev.name); - return 0; -fail_base_iomap: - release_mem_region(res->start, resource_size(res)); - i--; -fail_nobase_res: - if (isif_cfg.base_addr) - iounmap(isif_cfg.base_addr); - if (isif_cfg.linear_tbl0_addr) - iounmap(isif_cfg.linear_tbl0_addr); - - while (i >= 0) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, resource_size(res)); - i--; - } -fail_mclk: - clk_put(isif_cfg.mclk); - vpfe_unregister_ccdc_device(&isif_hw_dev); - return status; -} - -static int isif_remove(struct platform_device *pdev) -{ - struct resource *res; - int i = 0; - - iounmap(isif_cfg.base_addr); - iounmap(isif_cfg.linear_tbl0_addr); - iounmap(isif_cfg.linear_tbl1_addr); - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, resource_size(res)); - i++; - } - vpfe_unregister_ccdc_device(&isif_hw_dev); - return 0; -} - -static struct platform_driver isif_driver = { - .driver = { - .name = "isif", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(isif_remove), - .probe = isif_probe, -}; - -static int __init isif_init(void) -{ - return platform_driver_register(&isif_driver); -} - -static void isif_exit(void) -{ - platform_driver_unregister(&isif_driver); -} - -module_init(isif_init); -module_exit(isif_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/isif_regs.h b/drivers/media/video/davinci/isif_regs.h deleted file mode 100644 index aa69a46..0000000 --- a/drivers/media/video/davinci/isif_regs.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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 _ISIF_REGS_H -#define _ISIF_REGS_H - -/* ISIF registers relative offsets */ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDW 0x08 -#define VDW 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define LNH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define LNV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define CADU 0x3c -#define CADL 0x40 -#define LINCFG0 0x44 -#define LINCFG1 0x48 -#define CCOLP 0x4c -#define CRGAIN 0x50 -#define CGRGAIN 0x54 -#define CGBGAIN 0x58 -#define CBGAIN 0x5c -#define COFSTA 0x60 -#define FLSHCFG0 0x64 -#define FLSHCFG1 0x68 -#define FLSHCFG2 0x6c -#define VDINT0 0x70 -#define VDINT1 0x74 -#define VDINT2 0x78 -#define MISC 0x7c -#define CGAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -/***************************************************** -* Defect Correction registers -*****************************************************/ -#define DFCCTL 0x8c -#define VDFSATLV 0x90 -#define DFCMEMCTL 0x94 -#define DFCMEM0 0x98 -#define DFCMEM1 0x9c -#define DFCMEM2 0xa0 -#define DFCMEM3 0xa4 -#define DFCMEM4 0xa8 -/**************************************************** -* Black Clamp registers -****************************************************/ -#define CLAMPCFG 0xac -#define CLDCOFST 0xb0 -#define CLSV 0xb4 -#define CLHWIN0 0xb8 -#define CLHWIN1 0xbc -#define CLHWIN2 0xc0 -#define CLVRV 0xc4 -#define CLVWIN0 0xc8 -#define CLVWIN1 0xcc -#define CLVWIN2 0xd0 -#define CLVWIN3 0xd4 -/**************************************************** -* Lense Shading Correction -****************************************************/ -#define DATAHOFST 0xd8 -#define DATAVOFST 0xdc -#define LSCHVAL 0xe0 -#define LSCVVAL 0xe4 -#define TWODLSCCFG 0xe8 -#define TWODLSCOFST 0xec -#define TWODLSCINI 0xf0 -#define TWODLSCGRBU 0xf4 -#define TWODLSCGRBL 0xf8 -#define TWODLSCGROF 0xfc -#define TWODLSCORBU 0x100 -#define TWODLSCORBL 0x104 -#define TWODLSCOROF 0x108 -#define TWODLSCIRQEN 0x10c -#define TWODLSCIRQST 0x110 -/**************************************************** -* Data formatter -****************************************************/ -#define FMTCFG 0x114 -#define FMTPLEN 0x118 -#define FMTSPH 0x11c -#define FMTLNH 0x120 -#define FMTSLV 0x124 -#define FMTLNV 0x128 -#define FMTRLEN 0x12c -#define FMTHCNT 0x130 -#define FMTAPTR_BASE 0x134 -/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ -#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) -#define FMTPGMVF0 0x174 -#define FMTPGMVF1 0x178 -#define FMTPGMAPU0 0x17c -#define FMTPGMAPU1 0x180 -#define FMTPGMAPS0 0x184 -#define FMTPGMAPS1 0x188 -#define FMTPGMAPS2 0x18c -#define FMTPGMAPS3 0x190 -#define FMTPGMAPS4 0x194 -#define FMTPGMAPS5 0x198 -#define FMTPGMAPS6 0x19c -#define FMTPGMAPS7 0x1a0 -/************************************************ -* Color Space Converter -************************************************/ -#define CSCCTL 0x1a4 -#define CSCM0 0x1a8 -#define CSCM1 0x1ac -#define CSCM2 0x1b0 -#define CSCM3 0x1b4 -#define CSCM4 0x1b8 -#define CSCM5 0x1bc -#define CSCM6 0x1c0 -#define CSCM7 0x1c4 -#define OBWIN0 0x1c8 -#define OBWIN1 0x1cc -#define OBWIN2 0x1d0 -#define OBWIN3 0x1d4 -#define OBVAL0 0x1d8 -#define OBVAL1 0x1dc -#define OBVAL2 0x1e0 -#define OBVAL3 0x1e4 -#define OBVAL4 0x1e8 -#define OBVAL5 0x1ec -#define OBVAL6 0x1f0 -#define OBVAL7 0x1f4 -#define CLKCTL 0x1f8 - -/* Masks & Shifts below */ -#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 - -/* gain - offset masks */ -#define GAIN_INTEGER_SHIFT 9 -#define OFFSET_MASK 0xFFF -#define GAIN_SDRAM_EN_SHIFT 12 -#define GAIN_IPIPE_EN_SHIFT 13 -#define GAIN_H3A_EN_SHIFT 14 -#define OFST_SDRAM_EN_SHIFT 8 -#define OFST_IPIPE_EN_SHIFT 9 -#define OFST_H3A_EN_SHIFT 10 -#define GAIN_OFFSET_EN_MASK 0x7700 - -/* Culling */ -#define CULL_PAT_EVEN_LINE_SHIFT 8 - -/* CCDCFG register */ -#define ISIF_YCINSWP_RAW (0x00 << 4) -#define ISIF_YCINSWP_YCBCR (0x01 << 4) -#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) -#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) -#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) -#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) -#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) -#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) -#define ISIF_DATA_PACK_MASK 3 -#define ISIF_DATA_PACK16 0 -#define ISIF_DATA_PACK12 1 -#define ISIF_DATA_PACK8 2 -#define ISIF_PIX_ORDER_SHIFT 11 -#define ISIF_BW656_ENABLE (0x01 << 5) - -/* MODESET registers */ -#define ISIF_VDHDOUT_INPUT (0x00 << 0) -#define ISIF_INPUT_SHIFT 12 -#define ISIF_RAW_INPUT_MODE 0 -#define ISIF_FID_POL_SHIFT 4 -#define ISIF_HD_POL_SHIFT 3 -#define ISIF_VD_POL_SHIFT 2 -#define ISIF_DATAPOL_NORMAL 0 -#define ISIF_DATAPOL_SHIFT 6 -#define ISIF_EXWEN_DISABLE 0 -#define ISIF_EXWEN_SHIFT 5 -#define ISIF_FRM_FMT_SHIFT 7 -#define ISIF_DATASFT_SHIFT 8 -#define ISIF_LPF_SHIFT 14 -#define ISIF_LPF_MASK 1 - -/* GAMMAWD registers */ -#define ISIF_ALAW_GAMA_WD_MASK 0xF -#define ISIF_ALAW_GAMA_WD_SHIFT 1 -#define ISIF_ALAW_ENABLE 1 -#define ISIF_GAMMAWD_CFA_SHIFT 5 - -/* HSIZE registers */ -#define ISIF_HSIZE_FLIP_MASK 1 -#define ISIF_HSIZE_FLIP_SHIFT 12 - -/* MISC registers */ -#define ISIF_DPCM_EN_SHIFT 12 -#define ISIF_DPCM_PREDICTOR_SHIFT 13 - -/* Black clamp related */ -#define ISIF_BC_MODE_COLOR_SHIFT 4 -#define ISIF_HORZ_BC_MODE_SHIFT 1 -#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 -#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 -#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 -#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 -#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 -#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 - -/* VDFC registers */ -#define ISIF_VDFC_EN_SHIFT 4 -#define ISIF_VDFC_CORR_MOD_SHIFT 5 -#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 -#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 -#define ISIF_VDFC_POS_MASK 0x1FFF -#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 - -/* CSC registers */ -#define ISIF_CSC_COEF_INTEG_MASK 7 -#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f -#define ISIF_CSC_COEF_INTEG_SHIFT 5 -#define ISIF_CSCM_MSB_SHIFT 8 -#define ISIF_DF_CSC_SPH_MASK 0x1FFF -#define ISIF_DF_CSC_LNH_MASK 0x1FFF -#define ISIF_DF_CSC_SLV_MASK 0x1FFF -#define ISIF_DF_CSC_LNV_MASK 0x1FFF -#define ISIF_DF_NUMLINES 0x7FFF -#define ISIF_DF_NUMPIX 0x1FFF - -/* Offsets for LSC/DFC/Gain */ -#define ISIF_DATA_H_OFFSET_MASK 0x1FFF -#define ISIF_DATA_V_OFFSET_MASK 0x1FFF - -/* Linearization */ -#define ISIF_LIN_CORRSFT_SHIFT 4 -#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 - - -/* Pattern registers */ -#define ISIF_PG_EN (1 << 3) -#define ISIF_SEL_PG_SRC (3 << 4) -#define ISIF_PG_VD_POL_SHIFT 0 -#define ISIF_PG_HD_POL_SHIFT 1 - -/*random other junk*/ -#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) -#define ISIF_SYNCEN_WEN_MASK (1 << 1) -#define ISIF_SYNCEN_WEN_SHIFT 1 - -#endif diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c deleted file mode 100644 index 51f6213..0000000 --- a/drivers/media/video/davinci/vpfe_capture.c +++ /dev/null @@ -1,2080 +0,0 @@ -/* - * 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 - * - * Driver name : VPFE Capture driver - * VPFE Capture driver allows applications to capture and stream video - * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as - * TVP5146 or Raw Bayer RGB image data from an image sensor - * such as Microns' MT9T001, MT9T031 etc. - * - * These SoCs have, in common, a Video Processing Subsystem (VPSS) that - * consists of a Video Processing Front End (VPFE) for capturing - * video/raw image data and Video Processing Back End (VPBE) for displaying - * YUV data through an in-built analog encoder or Digital LCD port. This - * driver is for capture through VPFE. A typical EVM using these SoCs have - * following high level configuration. - * - * - * decoder(TVP5146/ YUV/ - * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) - * data input | | - * V | - * SDRAM | - * V - * Image Processor - * | - * V - * SDRAM - * The data flow happens from a decoder connected to the VPFE over a - * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface - * and to the input of VPFE through an optional MUX (if more inputs are - * to be interfaced on the EVM). The input data is first passed through - * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC - * does very little or no processing on YUV data and does pre-process Raw - * Bayer RGB data through modules such as Defect Pixel Correction (DFC) - * Color Space Conversion (CSC), data gain/offset etc. After this, data - * can be written to SDRAM or can be connected to the image processing - * block such as IPIPE (on DM355 only). - * - * Features supported - * - MMAP IO - * - Capture using TVP5146 over BT.656 - * - support for interfacing decoders using sub device model - * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV - * data capture to SDRAM. - * TODO list - * - Support multiple REQBUF after open - * - Support for de-allocating buffers through REQBUF - * - Support for Raw Bayer RGB capture - * - Support for chaining Image Processor - * - Support for static allocation of buffers - * - Support for USERPTR IO - * - Support for STREAMON before QBUF - * - Support for control ioctls - */ -#include -#include -#include -#include -#include -#include -#include -#include "ccdc_hw_device.h" - -static int debug; -static u32 numbuffers = 3; -static u32 bufsize = (720 * 576 * 2); - -module_param(numbuffers, uint, S_IRUGO); -module_param(bufsize, uint, S_IRUGO); -module_param(debug, int, 0644); - -MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); -MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/* standard information */ -struct vpfe_standard { - v4l2_std_id std_id; - unsigned int width; - unsigned int height; - struct v4l2_fract pixelaspect; - /* 0 - progressive, 1 - interlaced */ - int frame_format; -}; - -/* ccdc configuration */ -struct ccdc_config { - /* This make sure vpfe is probed and ready to go */ - int vpfe_probed; - /* name of ccdc device */ - char name[32]; -}; - -/* data structures */ -static struct vpfe_config_params config_params = { - .min_numbuffers = 3, - .numbuffers = 3, - .min_bufsize = 720 * 480 * 2, - .device_bufsize = 720 * 576 * 2, -}; - -/* ccdc device registered */ -static struct ccdc_hw_device *ccdc_dev; -/* lock for accessing ccdc information */ -static DEFINE_MUTEX(ccdc_lock); -/* ccdc configuration */ -static struct ccdc_config *ccdc_cfg; - -const struct vpfe_standard vpfe_standards[] = { - {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, - {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, -}; - -/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ -static const struct vpfe_pixel_format vpfe_pix_fmts[] = { - { - .fmtdesc = { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit A-Law compr.", - .pixelformat = V4L2_PIX_FMT_SBGGR8, - }, - .bpp = 1, - }, - { - .fmtdesc = { - .index = 1, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb - 16bit", - .pixelformat = V4L2_PIX_FMT_SBGGR16, - }, - .bpp = 2, - }, - { - .fmtdesc = { - .index = 2, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Bayer GrRBGb 8bit DPCM compr.", - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - }, - .bpp = 1, - }, - { - .fmtdesc = { - .index = 3, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved UYVY", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, - .bpp = 2, - }, - { - .fmtdesc = { - .index = 4, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "YCbCr 4:2:2 Interleaved YUYV", - .pixelformat = V4L2_PIX_FMT_YUYV, - }, - .bpp = 2, - }, - { - .fmtdesc = { - .index = 5, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "Y/CbCr 4:2:0 - Semi planar", - .pixelformat = V4L2_PIX_FMT_NV12, - }, - .bpp = 1, - }, -}; - -/* - * vpfe_lookup_pix_format() - * lookup an entry in the vpfe pix format table based on pix_format - */ -static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { - if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) - return &vpfe_pix_fmts[i]; - } - return NULL; -} - -/* - * vpfe_register_ccdc_device. CCDC module calls this to - * register with vpfe capture - */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) -{ - int ret = 0; - printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); - - BUG_ON(!dev->hw_ops.open); - BUG_ON(!dev->hw_ops.enable); - BUG_ON(!dev->hw_ops.set_hw_if_params); - BUG_ON(!dev->hw_ops.configure); - BUG_ON(!dev->hw_ops.set_buftype); - BUG_ON(!dev->hw_ops.get_buftype); - BUG_ON(!dev->hw_ops.enum_pix); - BUG_ON(!dev->hw_ops.set_frame_format); - BUG_ON(!dev->hw_ops.get_frame_format); - BUG_ON(!dev->hw_ops.get_pixel_format); - BUG_ON(!dev->hw_ops.set_pixel_format); - BUG_ON(!dev->hw_ops.set_params); - BUG_ON(!dev->hw_ops.set_image_window); - BUG_ON(!dev->hw_ops.get_image_window); - BUG_ON(!dev->hw_ops.get_line_length); - BUG_ON(!dev->hw_ops.getfid); - - mutex_lock(&ccdc_lock); - if (NULL == ccdc_cfg) { - /* - * TODO. Will this ever happen? if so, we need to fix it. - * Proabably we need to add the request to a linked list and - * walk through it during vpfe probe - */ - printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -EFAULT; - goto unlock; - } - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - ret = -EINVAL; - goto unlock; - } - - if (ccdc_dev) { - printk(KERN_ERR "ccdc already registered\n"); - ret = -EINVAL; - goto unlock; - } - - ccdc_dev = dev; -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} -EXPORT_SYMBOL(vpfe_register_ccdc_device); - -/* - * vpfe_unregister_ccdc_device. CCDC module calls this to - * unregister with vpfe capture - */ -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) -{ - if (NULL == dev) { - printk(KERN_ERR "invalid ccdc device ptr\n"); - return; - } - - printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", - dev->name); - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - return; - } - - mutex_lock(&ccdc_lock); - ccdc_dev = NULL; - mutex_unlock(&ccdc_lock); - return; -} -EXPORT_SYMBOL(vpfe_unregister_ccdc_device); - -/* - * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings - */ -static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, - struct v4l2_format *f) -{ - struct v4l2_rect image_win; - enum ccdc_buftype buf_type; - enum ccdc_frmfmt frm_fmt; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ccdc_dev->hw_ops.get_image_window(&image_win); - f->fmt.pix.width = image_win.width; - f->fmt.pix.height = image_win.height; - f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * - f->fmt.pix.height; - buf_type = ccdc_dev->hw_ops.get_buftype(); - f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format(); - frm_fmt = ccdc_dev->hw_ops.get_frame_format(); - 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 { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n"); - return -EINVAL; - } - } else { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n"); - return -EINVAL; - } - return 0; -} - -/* - * vpfe_config_ccdc_image_format() - * For a pix format, configure ccdc to setup the capture - */ -static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; - int ret = 0; - - if (ccdc_dev->hw_ops.set_pixel_format( - vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "couldn't set pix format in ccdc\n"); - return -EINVAL; - } - /* configure the image window */ - ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); - - switch (vpfe_dev->fmt.fmt.pix.field) { - case V4L2_FIELD_INTERLACED: - /* do nothing, since it is default */ - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_INTERLEAVED); - break; - case V4L2_FIELD_NONE: - frm_fmt = CCDC_FRMFMT_PROGRESSIVE; - /* buffer type only applicable for interlaced scan */ - break; - case V4L2_FIELD_SEQ_TB: - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_SEPARATED); - break; - default: - return -EINVAL; - } - - /* set the frame format */ - if (!ret) - ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); - return ret; -} -/* - * vpfe_config_image_format() - * For a given standard, this functions sets up the default - * pix format & crop values in the vpfe device and ccdc. It first - * starts with defaults based values from the standard table. - * It then checks if sub device support g_fmt and then override the - * values based on that.Sets crop values to match with scan resolution - * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the - * values in ccdc - */ -static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, - const v4l2_std_id *std_id) -{ - struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; - int i, ret = 0; - - for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { - if (vpfe_standards[i].std_id & *std_id) { - vpfe_dev->std_info.active_pixels = - vpfe_standards[i].width; - vpfe_dev->std_info.active_lines = - vpfe_standards[i].height; - vpfe_dev->std_info.frame_format = - vpfe_standards[i].frame_format; - vpfe_dev->std_index = i; - break; - } - } - - if (i == ARRAY_SIZE(vpfe_standards)) { - v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); - return -EINVAL; - } - - vpfe_dev->crop.top = 0; - vpfe_dev->crop.left = 0; - vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; - vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; - vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width; - vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height; - - /* first field and frame format based on standard frame format */ - if (vpfe_dev->std_info.frame_format) { - vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - /* assume V4L2_PIX_FMT_UYVY as default */ - vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; - } else { - vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE; - /* assume V4L2_PIX_FMT_SBGGR8 */ - vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; - } - - /* if sub device supports g_fmt, override the defaults */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt); - - if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&vpfe_dev->v4l2_dev, - "error in getting g_fmt from sub device\n"); - return ret; - } - - /* Sets the values in CCDC */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - if (ret) - return ret; - - /* Update the values of sizeimage and bytesperline */ - if (!ret) { - vpfe_dev->fmt.fmt.pix.bytesperline = - ccdc_dev->hw_ops.get_line_length(); - vpfe_dev->fmt.fmt.pix.sizeimage = - vpfe_dev->fmt.fmt.pix.bytesperline * - vpfe_dev->fmt.fmt.pix.height; - } - return ret; -} - -static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) -{ - int ret = 0; - - /* set first input of current subdevice as the current input */ - vpfe_dev->current_input = 0; - - /* set default standard */ - vpfe_dev->std_index = 0; - - /* Configure the default format information */ - ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); - if (ret) - return ret; - - /* now open the ccdc device to initialize it */ - mutex_lock(&ccdc_lock); - if (NULL == ccdc_dev) { - v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); - ret = -ENODEV; - goto unlock; - } - - if (!try_module_get(ccdc_dev->owner)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); - ret = -ENODEV; - goto unlock; - } - ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); - if (!ret) - vpfe_dev->initialized = 1; - - /* Clear all VPFE/CCDC interrupts */ - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(-1); - -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} - -/* - * vpfe_open : It creates object of file handle structure and - * stores it in private_data member of filepointer - */ -static int vpfe_open(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); - - if (!vpfe_dev->cfg->num_subdevs) { - v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); - return -ENODEV; - } - - /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); - if (NULL == fh) { - v4l2_err(&vpfe_dev->v4l2_dev, - "unable to allocate memory for file handle object\n"); - return -ENOMEM; - } - /* store pointer to fh in private_data member of file */ - file->private_data = fh; - fh->vpfe_dev = vpfe_dev; - mutex_lock(&vpfe_dev->lock); - /* If decoder is not initialized. initialize it */ - if (!vpfe_dev->initialized) { - if (vpfe_initialize_device(vpfe_dev)) { - mutex_unlock(&vpfe_dev->lock); - return -ENODEV; - } - } - /* Increment device usrs counter */ - vpfe_dev->usrs++; - /* Set io_allowed member to false */ - fh->io_allowed = 0; - /* Initialize priority of this instance to default priority */ - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&vpfe_dev->prio, &fh->prio); - mutex_unlock(&vpfe_dev->lock); - return 0; -} - -static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vpfe_dev->next_frm->queue); - vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; - addr = videobuf_to_dma_contig(vpfe_dev->next_frm); - - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - addr += vpfe_dev->field_off; - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) -{ - struct timeval timevalue; - - do_gettimeofday(&timevalue); - vpfe_dev->cur_frm->ts = timevalue; - vpfe_dev->cur_frm->state = VIDEOBUF_DONE; - vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; - wake_up_interruptible(&vpfe_dev->cur_frm->done); - vpfe_dev->cur_frm = vpfe_dev->next_frm; -} - -/* ISR for VINT0*/ -static irqreturn_t vpfe_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - enum v4l2_field field; - int fid; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); - field = vpfe_dev->fmt.fmt.pix.field; - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) - goto clear_intr; - - /* only for 6446 this will be applicable */ - if (NULL != ccdc_dev->hw_ops.reset) - ccdc_dev->hw_ops.reset(); - - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "frame format is progressive...\n"); - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - goto clear_intr; - } - - /* interlaced or TB capture check which field we are in hardware */ - fid = ccdc_dev->hw_ops.getfid(); - - /* switch the software maintained field id */ - vpfe_dev->field_id ^= 1; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", - fid, vpfe_dev->field_id); - if (fid == vpfe_dev->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_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - /* - * based on whether the two fields are stored - * interleavely or separately in memory, reconfigure - * the CCDC memory address - */ - if (field == V4L2_FIELD_SEQ_TB) { - vpfe_schedule_bottom_field(vpfe_dev); - } - goto clear_intr; - } - /* - * 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 - */ - spin_lock(&vpfe_dev->dma_queue_lock); - if (!list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - vpfe_dev->field_id = fid; - } -clear_intr: - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -/* vdint1_isr - isr handler for VINT1 interrupt */ -static irqreturn_t vdint1_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) { - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - return IRQ_HANDLED; - } - - spin_lock(&vpfe_dev->dma_queue_lock); - if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && - !list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); -} - -static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { - return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, - IRQF_DISABLED, "vpfe_capture1", - vpfe_dev); - } - return 0; -} - -/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ -static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - vpfe_dev->started = 0; - ccdc_dev->hw_ops.enable(0); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(0); -} - -/* - * vpfe_release : This function deletes buffer queue, frees the - * buffers and the vpfe file handle - */ -static int vpfe_release(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); - - /* Get the device lock */ - mutex_lock(&vpfe_dev->lock); - /* if this instance is doing IO */ - if (fh->io_allowed) { - if (vpfe_dev->started) { - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, - video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, - "stream off failed in subdev\n"); - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - videobuf_streamoff(&vpfe_dev->buffer_queue); - } - vpfe_dev->io_usrs = 0; - vpfe_dev->numbuffers = config_params.numbuffers; - } - - /* Decrement device usrs counter */ - vpfe_dev->usrs--; - /* Close the priority */ - v4l2_prio_close(&vpfe_dev->prio, &fh->prio); - /* If this is the last file handle */ - if (!vpfe_dev->usrs) { - vpfe_dev->initialized = 0; - if (ccdc_dev->hw_ops.close) - ccdc_dev->hw_ops.close(vpfe_dev->pdev); - module_put(ccdc_dev->owner); - } - mutex_unlock(&vpfe_dev->lock); - file->private_data = NULL; - /* Free memory allocated to file handle object */ - kfree(fh); - return 0; -} - -/* - * vpfe_mmap : It is used to map kernel space buffers - * into user spaces - */ -static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* Get the device object and file handle object */ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); - - return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); -} - -/* - * vpfe_poll: It is used for select/poll system call - */ -static unsigned int vpfe_poll(struct file *file, poll_table *wait) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); - - if (vpfe_dev->started) - return videobuf_poll_stream(file, - &vpfe_dev->buffer_queue, wait); - return 0; -} - -/* vpfe capture driver file operations */ -static const struct v4l2_file_operations vpfe_fops = { - .owner = THIS_MODULE, - .open = vpfe_open, - .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpfe_mmap, - .poll = vpfe_poll -}; - -/* - * vpfe_check_format() - * This function adjust the input pixel format as per hardware - * capabilities and update the same in pixfmt. - * Following algorithm used :- - * - * If given pixformat is not in the vpfe list of pix formats or not - * supported by the hardware, current value of pixformat in the device - * is used - * If given field is not supported, then current field is used. If field - * is different from current, then it is matched with that from sub device. - * Minimum height is 2 lines for interlaced or tb field and 1 line for - * progressive. Maximum height is clamped to active active lines of scan - * Minimum width is 32 bytes in memory and width is clamped to active - * pixels of scan. - * bytesperline is a multiple of 32. - */ -static const struct vpfe_pixel_format * - vpfe_check_format(struct vpfe_device *vpfe_dev, - struct v4l2_pix_format *pixfmt) -{ - u32 min_height = 1, min_width = 32, max_width, max_height; - const struct vpfe_pixel_format *vpfe_pix_fmt; - u32 pix; - int temp, found; - - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - if (NULL == vpfe_pix_fmt) { - /* - * use current pixel format in the vpfe device. We - * will find this pix format in the table - */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check if hw supports it */ - temp = 0; - found = 0; - while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { - if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { - found = 1; - break; - } - temp++; - } - - if (!found) { - /* use current pixel format */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - /* - * Since this is currently used in the vpfe device, we - * will find this pix format in the table - */ - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check what field format is supported */ - if (pixfmt->field == V4L2_FIELD_ANY) { - /* if field is any, use current value as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - } - - /* - * if field is not same as current field in the vpfe device - * try matching the field with the sub device field - */ - if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { - /* - * If field value is not in the supported fields, use current - * field used in the device as default - */ - switch (pixfmt->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_SEQ_TB: - /* if sub device is supporting progressive, use that */ - if (!vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_NONE; - break; - case V4L2_FIELD_NONE: - if (vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_INTERLACED; - break; - - default: - /* use current field as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - break; - } - } - - /* Now adjust image resolutions supported */ - if (pixfmt->field == V4L2_FIELD_INTERLACED || - pixfmt->field == V4L2_FIELD_SEQ_TB) - min_height = 2; - - max_width = vpfe_dev->std_info.active_pixels; - max_height = vpfe_dev->std_info.active_lines; - min_width /= vpfe_pix_fmt->bpp; - - v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); - - pixfmt->width = clamp((pixfmt->width), min_width, max_width); - pixfmt->height = clamp((pixfmt->height), min_height, max_height); - - /* If interlaced, adjust height to be a multiple of 2 */ - if (pixfmt->field == V4L2_FIELD_INTERLACED) - pixfmt->height &= (~1); - /* - * recalculate bytesperline and sizeimage since width - * and height might have changed - */ - pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) - & ~31); - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - pixfmt->sizeimage = - pixfmt->bytesperline * pixfmt->height + - ((pixfmt->bytesperline * pixfmt->height) >> 1); - else - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" - " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, - pixfmt->bytesperline, pixfmt->sizeimage); - return vpfe_pix_fmt; -} - -static int vpfe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - - cap->version = VPFE_CAPTURE_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); - strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); - return 0; -} - -static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); - /* Fill in the information about format */ - *fmt = vpfe_dev->fmt; - return ret; -} - -static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmt; - int temp_index; - u32 pix; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); - - if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) - return -EINVAL; - - /* Fill in the information about format */ - pix_fmt = vpfe_lookup_pix_format(pix); - if (NULL != pix_fmt) { - temp_index = fmt->index; - *fmt = pix_fmt->fmtdesc; - fmt->index = temp_index; - return 0; - } - return -EINVAL; -} - -static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); - - /* If streaming is started, return error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); - return -EBUSY; - } - - /* Check for valid frame format */ - pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); - - if (NULL == pix_fmts) - return -EINVAL; - - /* store the pixel format in the device object */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* First detach any IRQ if currently attached */ - vpfe_detach_irq(vpfe_dev); - vpfe_dev->fmt = *fmt; - /* set image capture parameters in the ccdc */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); - - pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); - if (NULL == pix_fmts) - return -EINVAL; - return 0; -} - -/* - * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a - * given app input index - */ -static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, - int *subdev_index, - int *subdev_input_index, - int app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (app_input_index < (j + sdinfo->num_inputs)) { - *subdev_index = i; - *subdev_input_index = app_input_index - j; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -/* - * vpfe_get_app_input - Get app input index for a given subdev input index - * driver stores the input index of the current sub device and translate it - * when application request the current input - */ -static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, - int *app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { - if (vpfe_dev->current_input >= sdinfo->num_inputs) - return -1; - *app_input_index = j + vpfe_dev->current_input; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -static int vpfe_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int subdev, index ; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - - if (vpfe_get_subdev_input_index(vpfe_dev, - &subdev, - &index, - inp->index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" - " for the subdev\n"); - return -EINVAL; - } - sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; - memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); - return 0; -} - -static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); - - return vpfe_get_app_input_index(vpfe_dev, index); -} - - -static int vpfe_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int subdev_index, inp_index; - struct vpfe_route *route; - u32 input = 0, output = 0; - int ret = -EINVAL; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* - * If streaming is started return device busy - * error - */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); - ret = -EBUSY; - goto unlock_out; - } - - if (vpfe_get_subdev_input_index(vpfe_dev, - &subdev_index, - &inp_index, - index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); - goto unlock_out; - } - - sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; - route = &sdinfo->routes[inp_index]; - if (route && sdinfo->can_route) { - input = route->input; - output = route->output; - } - - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_routing, input, output, 0); - - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "vpfe_doioctl:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; - } - vpfe_dev->current_subdev = sdinfo; - vpfe_dev->current_input = index; - vpfe_dev->std_index = 0; - - /* set the bus/interface parameter for the sub device in ccdc */ - ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); - if (ret) - goto unlock_out; - - /* set the default image parameters in the device */ - ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - sdinfo = vpfe_dev->current_subdev; - if (ret) - return ret; - /* Call querystd function of decoder device */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, querystd, std_id); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); - - /* Call decoder driver function to set the standard */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - sdinfo = vpfe_dev->current_subdev; - /* If streaming is started, return device busy error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); - ret = -EBUSY; - goto unlock_out; - } - - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_std, *std_id); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); - goto unlock_out; - } - ret = vpfe_config_image_format(vpfe_dev, std_id); - -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); - - *std_id = vpfe_standards[vpfe_dev->std_index].std_id; - return 0; -} -/* - * Videobuf operations - */ -static int vpfe_videobuf_setup(struct videobuf_queue *vq, - unsigned int *count, - unsigned int *size) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); - *size = vpfe_dev->fmt.fmt.pix.sizeimage; - if (vpfe_dev->memory == V4L2_MEMORY_MMAP && - vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) - *size = config_params.device_bufsize; - - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "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) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long addr; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); - - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vpfe_dev->fmt.fmt.pix.width; - vb->height = vpfe_dev->fmt.fmt.pix.height; - vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; - vb->field = field; - - ret = videobuf_iolock(vq, vb, NULL);; - if (ret < 0) - return ret; - - addr = videobuf_to_dma_contig(vb); - /* Make sure user addresses are aligned to 32 bytes */ - if (!ALIGN(addr, 32)) - return -EINVAL; - - vb->state = VIDEOBUF_PREPARED; - } - return 0; -} - -static void vpfe_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and device object */ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - list_add_tail(&vb->queue, &vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; -} - -static void vpfe_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); - - /* - * We need to flush the buffer from the dma queue since - * they are de-allocated - */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - 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, -}; - -/* - * vpfe_reqbufs. currently support REQBUF only once opening - * the device. - */ -static int vpfe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (vpfe_dev->io_usrs != 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); - ret = -EBUSY; - goto unlock_out; - } - - vpfe_dev->memory = req_buf->memory; - videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, - &vpfe_videobuf_qops, - vpfe_dev->pdev, - &vpfe_dev->irqlock, - req_buf->type, - vpfe_dev->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), - fh); - - fh->io_allowed = 1; - vpfe_dev->io_usrs = 1; - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); - return -EINVAL; - } - /* Call videobuf_querybuf to get information */ - return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); -} - -static int vpfe_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* - * If this file handle is not allowed to do IO, - * return error - */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - return videobuf_qbuf(&vpfe_dev->buffer_queue, p); -} - -static int vpfe_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - return videobuf_dqbuf(&vpfe_dev->buffer_queue, - buf, file->f_flags & O_NONBLOCK); -} - -static int vpfe_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, queryctrl, qctrl); - -} - -static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, g_ctrl, ctrl); -} - -static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_ctrl, ctrl); -} - -/* - * vpfe_calculate_offsets : This function calculates buffers offset - * for top and bottom field - */ -static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) -{ - struct v4l2_rect image_win; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); - - ccdc_dev->hw_ops.get_image_window(&image_win); - vpfe_dev->field_off = image_win.height * image_win.width; -} - -/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ -static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - ccdc_dev->hw_ops.enable(1); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(1); - vpfe_dev->started = 1; -} - -/* - * vpfe_streamon. Assume the DMA queue is not empty. - * application is expected to call QBUF before calling - * this ioctl. If not, driver returns error - */ -static int vpfe_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - unsigned long addr; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 1); - - if (ret && (ret != -ENOIOCTLCMD)) { - v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); - return -EINVAL; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&vpfe_dev->buffer_queue.stream)) { - v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); - return -EIO; - } - - /* Call videobuf_streamon to start streaming * in videobuf */ - ret = videobuf_streamon(&vpfe_dev->buffer_queue); - if (ret) - return ret; - - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - goto streamoff; - /* Get the next frame from the buffer queue */ - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - vpfe_dev->cur_frm = vpfe_dev->next_frm; - /* Remove buffer from the buffer queue */ - list_del(&vpfe_dev->cur_frm->queue); - /* Mark state of the current frame to active */ - vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - vpfe_dev->field_id = 0; - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - - /* Calculate field offset */ - vpfe_calculate_offsets(vpfe_dev); - - if (vpfe_attach_irq(vpfe_dev) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in attaching interrupt handle\n"); - ret = -EFAULT; - goto unlock_out; - } - if (ccdc_dev->hw_ops.configure() < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in configuring ccdc\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); - vpfe_start_ccdc_capture(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -unlock_out: - mutex_unlock(&vpfe_dev->lock); -streamoff: - ret = videobuf_streamoff(&vpfe_dev->buffer_queue); - return ret; -} - -static int vpfe_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 0); - - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); - ret = videobuf_streamoff(&vpfe_dev->buffer_queue); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *crop) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); - - if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_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[vpfe_dev->std_index].width; - crop->bounds.height = crop->defrect.height = - vpfe_standards[vpfe_dev->std_index].height; - crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; - return 0; -} - -static int vpfe_g_crop(struct file *file, void *priv, - struct v4l2_crop *crop) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); - - crop->c = vpfe_dev->crop; - return 0; -} - -static int vpfe_s_crop(struct file *file, void *priv, - struct v4l2_crop *crop) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); - - if (vpfe_dev->started) { - /* make sure streaming is not started */ - v4l2_err(&vpfe_dev->v4l2_dev, - "Cannot change crop when streaming is ON\n"); - return -EBUSY; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (crop->c.top < 0 || crop->c.left < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "doesn't support negative values for top & left\n"); - ret = -EINVAL; - goto unlock_out; - } - - /* adjust the width to 16 pixel boundry */ - crop->c.width = ((crop->c.width + 15) & ~0xf); - - /* make sure parameters are valid */ - if ((crop->c.left + crop->c.width > - vpfe_dev->std_info.active_pixels) || - (crop->c.top + crop->c.height > - vpfe_dev->std_info.active_lines)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.set_image_window(&crop->c); - vpfe_dev->fmt.fmt.pix.width = crop->c.width; - vpfe_dev->fmt.fmt.pix.height = crop->c.height; - vpfe_dev->fmt.fmt.pix.bytesperline = - ccdc_dev->hw_ops.get_line_length(); - vpfe_dev->fmt.fmt.pix.sizeimage = - vpfe_dev->fmt.fmt.pix.bytesperline * - vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = crop->c; -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - - -static long vpfe_param_handler(struct file *file, void *priv, - int cmd, void *param) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); - - if (vpfe_dev->started) { - /* only allowed if streaming is not started */ - v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n"); - return -EBUSY; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - switch (cmd) { - case VPFE_CMD_S_CCDC_RAW_PARAMS: - v4l2_warn(&vpfe_dev->v4l2_dev, - "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); - ret = ccdc_dev->hw_ops.set_params(param); - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in setting parameters in CCDC\n"); - goto unlock_out; - } - if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Invalid image format at CCDC\n"); - goto unlock_out; - } - break; - default: - ret = -EINVAL; - } -unlock_out: - mutex_unlock(&vpfe_dev->lock); - 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_queryctrl = vpfe_queryctrl, - .vidioc_g_ctrl = vpfe_g_ctrl, - .vidioc_s_ctrl = vpfe_s_ctrl, - .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_cropcap = vpfe_cropcap, - .vidioc_g_crop = vpfe_g_crop, - .vidioc_s_crop = vpfe_s_crop, - .vidioc_default = vpfe_param_handler, -}; - -static struct vpfe_device *vpfe_initialize(void) -{ - struct vpfe_device *vpfe_dev; - - /* Default number of buffers should be 3 */ - if ((numbuffers > 0) && - (numbuffers < config_params.min_numbuffers)) - numbuffers = config_params.min_numbuffers; - - /* - * Set buffer size to min buffers size if invalid buffer size is - * given - */ - if (bufsize < config_params.min_bufsize) - bufsize = config_params.min_bufsize; - - config_params.numbuffers = numbuffers; - - if (numbuffers) - config_params.device_bufsize = bufsize; - - /* Allocate memory for device objects */ - vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); - - return vpfe_dev; -} - -/* - * vpfe_probe : This function creates device entries by register - * itself to the V4L2 driver and initializes fields of each - * device objects - */ -static __init int vpfe_probe(struct platform_device *pdev) -{ - struct vpfe_subdev_info *sdinfo; - struct vpfe_config *vpfe_cfg; - struct resource *res1; - struct vpfe_device *vpfe_dev; - struct i2c_adapter *i2c_adap; - struct video_device *vfd; - int ret = -ENOMEM, i, j; - int num_subdevs = 0; - - /* Get the pointer to the device object */ - vpfe_dev = vpfe_initialize(); - - if (!vpfe_dev) { - v4l2_err(pdev->dev.driver, - "Failed to allocate memory for vpfe_dev\n"); - return ret; - } - - vpfe_dev->pdev = &pdev->dev; - - if (NULL == pdev->dev.platform_data) { - v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENODEV; - goto probe_free_dev_mem; - } - - vpfe_cfg = pdev->dev.platform_data; - vpfe_dev->cfg = vpfe_cfg; - if (NULL == vpfe_cfg->ccdc || - NULL == vpfe_cfg->card_name || - NULL == vpfe_cfg->sub_devs) { - v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - mutex_lock(&ccdc_lock); - /* Allocate memory for ccdc configuration */ - ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); - if (NULL == ccdc_cfg) { - v4l2_err(pdev->dev.driver, - "Memory allocation failed for ccdc_cfg\n"); - goto probe_free_dev_mem; - } - - strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); - /* Get VINT0 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT0\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq0 = res1->start; - - /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT1\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq1 = res1->start; - - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, - "vpfe_capture0", vpfe_dev); - - if (0 != ret) { - v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_free_ccdc_cfg_mem; - } - - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - ret = -ENOMEM; - v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); - goto probe_out_release_irq; - } - - /* Initialize field of video device */ - vfd->release = video_device_release; - vfd->fops = &vpfe_fops; - vfd->ioctl_ops = &vpfe_ioctl_ops; - vfd->tvnorms = 0; - vfd->current_norm = V4L2_STD_PAL; - vfd->v4l2_dev = &vpfe_dev->v4l2_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 */ - vpfe_dev->video_dev = vfd; - - ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register v4l2 device.\n"); - goto probe_out_video_release; - } - v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); - spin_lock_init(&vpfe_dev->irqlock); - spin_lock_init(&vpfe_dev->dma_queue_lock); - mutex_init(&vpfe_dev->lock); - - /* Initialize field of the device objects */ - vpfe_dev->numbuffers = config_params.numbuffers; - - /* Initialize prio member of device object */ - v4l2_prio_init(&vpfe_dev->prio); - /* register video device */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "trying to register vpfe device.\n"); - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "video_dev=%x\n", (int)&vpfe_dev->video_dev); - vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = video_register_device(vpfe_dev->video_dev, - VFL_TYPE_GRABBER, -1); - - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register video device.\n"); - goto probe_out_v4l2_unregister; - } - - v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpfe_dev); - /* set driver private data */ - video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); - i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); - num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, - GFP_KERNEL); - if (NULL == vpfe_dev->sd) { - v4l2_err(&vpfe_dev->v4l2_dev, - "unable to allocate memory for subdevice pointers\n"); - ret = -ENOMEM; - goto probe_out_video_unregister; - } - - for (i = 0; i < num_subdevs; i++) { - struct v4l2_input *inps; - - sdinfo = &vpfe_cfg->sub_devs[i]; - - /* Load up the subdevice */ - vpfe_dev->sd[i] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, - sdinfo->name, - &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[i]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->name); - vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; - /* update tvnorms from the sub devices */ - for (j = 0; j < sdinfo->num_inputs; j++) { - inps = &sdinfo->inputs[j]; - vfd->tvnorms |= inps->std; - } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s register fails\n", - sdinfo->name); - goto probe_sd_out; - } - } - - /* set first sub device as current one */ - vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; - - /* We have at least one sub device to work with */ - mutex_unlock(&ccdc_lock); - return 0; - -probe_sd_out: - kfree(vpfe_dev->sd); -probe_out_video_unregister: - video_unregister_device(vpfe_dev->video_dev); -probe_out_v4l2_unregister: - v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_video_release: - if (!video_is_registered(vpfe_dev->video_dev)) - video_device_release(vpfe_dev->video_dev); -probe_out_release_irq: - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_free_ccdc_cfg_mem: - mutex_unlock(&ccdc_lock); - kfree(ccdc_cfg); -probe_free_dev_mem: - kfree(vpfe_dev); - return ret; -} - -/* - * vpfe_remove : It un-register device from V4L2 driver - */ -static int __devexit vpfe_remove(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - - v4l2_info(pdev->dev.driver, "vpfe_remove\n"); - - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - kfree(vpfe_dev->sd); - v4l2_device_unregister(&vpfe_dev->v4l2_dev); - video_unregister_device(vpfe_dev->video_dev); - kfree(vpfe_dev); - kfree(ccdc_cfg); - return 0; -} - -static int vpfe_suspend(struct device *dev) -{ - return 0; -} - -static int vpfe_resume(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops vpfe_dev_pm_ops = { - .suspend = vpfe_suspend, - .resume = vpfe_resume, -}; - -static struct platform_driver vpfe_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - .owner = THIS_MODULE, - .pm = &vpfe_dev_pm_ops, - }, - .probe = vpfe_probe, - .remove = __devexit_p(vpfe_remove), -}; - -static __init int vpfe_init(void) -{ - printk(KERN_NOTICE "vpfe_init\n"); - /* Register driver to the kernel */ - return platform_driver_register(&vpfe_driver); -} - -/* - * vpfe_cleanup : This function un-registers device driver - */ -static void vpfe_cleanup(void) -{ - platform_driver_unregister(&vpfe_driver); -} - -module_init(vpfe_init); -module_exit(vpfe_cleanup); diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c deleted file mode 100644 index 1f532e3..0000000 --- a/drivers/media/video/davinci/vpif.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * vpif - DM646x Video Port Interface driver - * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) - * that receiveing video byte stream and two channels(2, 3) for video output. - * The hardware supports SDTV, HDTV formats, raw data capture. - * Currently, the driver supports NTSC and PAL standards. - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * 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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "vpif.h" - -MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); -MODULE_LICENSE("GPL"); - -#define VPIF_CH0_MAX_MODES (22) -#define VPIF_CH1_MAX_MODES (02) -#define VPIF_CH2_MAX_MODES (15) -#define VPIF_CH3_MAX_MODES (02) - -static resource_size_t res_len; -static struct resource *res; -spinlock_t vpif_lock; - -void __iomem *vpif_base; - -static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) -{ - if (val) - vpif_set_bit(reg, bit); - else - vpif_clr_bit(reg, bit); -} - -/* This structure is used to keep track of VPIF size register's offsets */ -struct vpif_registers { - u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; - u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; - u32 vanc1_size, width_mask, len_mask; - u8 max_modes; -}; - -static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { - /* Channel0 */ - { - VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, - VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, - VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, - VPIF_CH0_MAX_MODES, - }, - /* Channel1 */ - { - VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, - VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, - VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, - VPIF_CH1_MAX_MODES, - }, - /* Channel2 */ - { - VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, - VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, - VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, - VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, - VPIF_CH2_MAX_MODES - }, - /* Channel3 */ - { - VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, - VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, - VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, - VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, - VPIF_CH3_MAX_MODES - }, -}; - -/* vpif_set_mode_info: - * This function is used to set horizontal and vertical config parameters - * As per the standard in the channel, configure the values of L1, L3, - * L5, L7 L9, L11 in VPIF Register , also write width and height - */ -static void vpif_set_mode_info(const struct vpif_channel_config_params *config, - u8 channel_id, u8 config_channel_id) -{ - u32 value; - - value = (config->eav2sav & vpifregs[config_channel_id].width_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); - regw(value, vpifregs[channel_id].h_cfg); - - value = (config->l1 & vpifregs[config_channel_id].len_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->l3 & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg_00); - - value = (config->l5 & vpifregs[config_channel_id].len_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->l7 & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg_01); - - value = (config->l9 & vpifregs[config_channel_id].len_mask); - value <<= VPIF_CH_LEN_SHIFT; - value |= (config->l11 & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg_02); - - value = (config->vsize & vpifregs[config_channel_id].len_mask); - regw(value, vpifregs[channel_id].v_cfg); -} - -/* config_vpif_params - * Function to set the parameters of a channel - * Mainly modifies the channel ciontrol register - * It sets frame format, yc mux mode - */ -static void config_vpif_params(struct vpif_params *vpifparams, - u8 channel_id, u8 found) -{ - const struct vpif_channel_config_params *config = &vpifparams->std_info; - u32 value, ch_nip, reg; - u8 start, end; - int i; - - start = channel_id; - end = channel_id + found; - - for (i = start; i < end; i++) { - reg = vpifregs[i].ch_ctrl; - if (channel_id < 2) - ch_nip = VPIF_CAPTURE_CH_NIP; - else - ch_nip = VPIF_DISPLAY_CH_NIP; - - vpif_wr_bit(reg, ch_nip, config->frm_fmt); - vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); - vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, - vpifparams->video_params.storage_mode); - - /* Set raster scanning SDR Format */ - vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); - vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); - - if (channel_id > 1) /* Set the Pixel enable bit */ - vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); - else if (config->capture_format) { - /* Set the polarity of various pins */ - vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, - vpifparams->iface.fid_pol); - vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, - vpifparams->iface.vd_pol); - vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, - vpifparams->iface.hd_pol); - - value = regr(reg); - /* Set data width */ - value &= ((~(unsigned int)(0x3)) << - VPIF_CH_DATA_WIDTH_BIT); - value |= ((vpifparams->params.data_sz) << - VPIF_CH_DATA_WIDTH_BIT); - regw(value, reg); - } - - /* Write the pitch in the driver */ - regw((vpifparams->video_params.hpitch), - vpifregs[i].line_offset); - } -} - -/* vpif_set_video_params - * This function is used to set video parameters in VPIF register - */ -int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) -{ - const struct vpif_channel_config_params *config = &vpifparams->std_info; - int found = 1; - - vpif_set_mode_info(config, channel_id, channel_id); - if (!config->ycmux_mode) { - /* YC are on separate channels (HDTV formats) */ - vpif_set_mode_info(config, channel_id + 1, channel_id); - found = 2; - } - - config_vpif_params(vpifparams, channel_id, found); - - regw(0x80, VPIF_REQ_SIZE); - regw(0x01, VPIF_EMULATION_CTRL); - - return found; -} -EXPORT_SYMBOL(vpif_set_video_params); - -void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, - u8 channel_id) -{ - u32 value; - - value = 0x3F8 & (vbiparams->hstart0); - value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); - regw(value, vpifregs[channel_id].vanc0_strt); - - value = 0x3F8 & (vbiparams->hstart1); - value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); - regw(value, vpifregs[channel_id].vanc1_strt); - - value = 0x3F8 & (vbiparams->hsize0); - value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); - regw(value, vpifregs[channel_id].vanc0_size); - - value = 0x3F8 & (vbiparams->hsize1); - value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); - regw(value, vpifregs[channel_id].vanc1_size); - -} -EXPORT_SYMBOL(vpif_set_vbi_display_params); - -int vpif_channel_getfid(u8 channel_id) -{ - return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) - >> VPIF_CH_FID_SHIFT; -} -EXPORT_SYMBOL(vpif_channel_getfid); - -static int __init vpif_probe(struct platform_device *pdev) -{ - int status = 0; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; - - res_len = res->end - res->start + 1; - - res = request_mem_region(res->start, res_len, res->name); - if (!res) - return -EBUSY; - - vpif_base = ioremap(res->start, res_len); - if (!vpif_base) { - status = -EBUSY; - goto fail; - } - - spin_lock_init(&vpif_lock); - dev_info(&pdev->dev, "vpif probe success\n"); - return 0; - -fail: - release_mem_region(res->start, res_len); - return status; -} - -static int __devexit vpif_remove(struct platform_device *pdev) -{ - iounmap(vpif_base); - release_mem_region(res->start, res_len); - return 0; -} - -static struct platform_driver vpif_driver = { - .driver = { - .name = "vpif", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(vpif_remove), - .probe = vpif_probe, -}; - -static void vpif_exit(void) -{ - platform_driver_unregister(&vpif_driver); -} - -static int __init vpif_init(void) -{ - return platform_driver_register(&vpif_driver); -} -subsys_initcall(vpif_init); -module_exit(vpif_exit); - diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h deleted file mode 100644 index 188841b..0000000 --- a/drivers/media/video/davinci/vpif.h +++ /dev/null @@ -1,642 +0,0 @@ -/* - * VPIF header file - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * 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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef VPIF_H -#define VPIF_H - -#include -#include -#include -#include - -/* Maximum channel allowed */ -#define VPIF_NUM_CHANNELS (4) -#define VPIF_CAPTURE_NUM_CHANNELS (2) -#define VPIF_DISPLAY_NUM_CHANNELS (2) - -/* Macros to read/write registers */ -extern void __iomem *vpif_base; -extern spinlock_t vpif_lock; - -#define regr(reg) readl((reg) + vpif_base) -#define regw(value, reg) writel(value, (reg + vpif_base)) - -/* Register Addresss Offsets */ -#define VPIF_PID (0x0000) -#define VPIF_CH0_CTRL (0x0004) -#define VPIF_CH1_CTRL (0x0008) -#define VPIF_CH2_CTRL (0x000C) -#define VPIF_CH3_CTRL (0x0010) - -#define VPIF_INTEN (0x0020) -#define VPIF_INTEN_SET (0x0024) -#define VPIF_INTEN_CLR (0x0028) -#define VPIF_STATUS (0x002C) -#define VPIF_STATUS_CLR (0x0030) -#define VPIF_EMULATION_CTRL (0x0034) -#define VPIF_REQ_SIZE (0x0038) - -#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040) -#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044) -#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048) -#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c) -#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050) -#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054) -#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058) -#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c) -#define VPIF_CH0_SP_CFG (0x0060) -#define VPIF_CH0_IMG_ADD_OFST (0x0064) -#define VPIF_CH0_HANC_ADD_OFST (0x0068) -#define VPIF_CH0_H_CFG (0x006c) -#define VPIF_CH0_V_CFG_00 (0x0070) -#define VPIF_CH0_V_CFG_01 (0x0074) -#define VPIF_CH0_V_CFG_02 (0x0078) -#define VPIF_CH0_V_CFG_03 (0x007c) - -#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080) -#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084) -#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088) -#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c) -#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090) -#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094) -#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098) -#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c) -#define VPIF_CH1_SP_CFG (0x00a0) -#define VPIF_CH1_IMG_ADD_OFST (0x00a4) -#define VPIF_CH1_HANC_ADD_OFST (0x00a8) -#define VPIF_CH1_H_CFG (0x00ac) -#define VPIF_CH1_V_CFG_00 (0x00b0) -#define VPIF_CH1_V_CFG_01 (0x00b4) -#define VPIF_CH1_V_CFG_02 (0x00b8) -#define VPIF_CH1_V_CFG_03 (0x00bc) - -#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0) -#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4) -#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8) -#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc) -#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0) -#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4) -#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8) -#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc) -#define VPIF_CH2_SP_CFG (0x00e0) -#define VPIF_CH2_IMG_ADD_OFST (0x00e4) -#define VPIF_CH2_HANC_ADD_OFST (0x00e8) -#define VPIF_CH2_H_CFG (0x00ec) -#define VPIF_CH2_V_CFG_00 (0x00f0) -#define VPIF_CH2_V_CFG_01 (0x00f4) -#define VPIF_CH2_V_CFG_02 (0x00f8) -#define VPIF_CH2_V_CFG_03 (0x00fc) -#define VPIF_CH2_HANC0_STRT (0x0100) -#define VPIF_CH2_HANC0_SIZE (0x0104) -#define VPIF_CH2_HANC1_STRT (0x0108) -#define VPIF_CH2_HANC1_SIZE (0x010c) -#define VPIF_CH2_VANC0_STRT (0x0110) -#define VPIF_CH2_VANC0_SIZE (0x0114) -#define VPIF_CH2_VANC1_STRT (0x0118) -#define VPIF_CH2_VANC1_SIZE (0x011c) - -#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140) -#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144) -#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148) -#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c) -#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150) -#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154) -#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158) -#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c) -#define VPIF_CH3_SP_CFG (0x0160) -#define VPIF_CH3_IMG_ADD_OFST (0x0164) -#define VPIF_CH3_HANC_ADD_OFST (0x0168) -#define VPIF_CH3_H_CFG (0x016c) -#define VPIF_CH3_V_CFG_00 (0x0170) -#define VPIF_CH3_V_CFG_01 (0x0174) -#define VPIF_CH3_V_CFG_02 (0x0178) -#define VPIF_CH3_V_CFG_03 (0x017c) -#define VPIF_CH3_HANC0_STRT (0x0180) -#define VPIF_CH3_HANC0_SIZE (0x0184) -#define VPIF_CH3_HANC1_STRT (0x0188) -#define VPIF_CH3_HANC1_SIZE (0x018c) -#define VPIF_CH3_VANC0_STRT (0x0190) -#define VPIF_CH3_VANC0_SIZE (0x0194) -#define VPIF_CH3_VANC1_STRT (0x0198) -#define VPIF_CH3_VANC1_SIZE (0x019c) - -#define VPIF_IODFT_CTRL (0x01c0) - -/* Functions for bit Manipulation */ -static inline void vpif_set_bit(u32 reg, u32 bit) -{ - regw((regr(reg)) | (0x01 << bit), reg); -} - -static inline void vpif_clr_bit(u32 reg, u32 bit) -{ - regw(((regr(reg)) & ~(0x01 << bit)), reg); -} - -/* Macro for Generating mask */ -#ifdef GENERATE_MASK -#undef GENERATE_MASK -#endif - -#define GENERATE_MASK(bits, pos) \ - ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos) - -/* Bit positions in the channel control registers */ -#define VPIF_CH_DATA_MODE_BIT (2) -#define VPIF_CH_YC_MUX_BIT (3) -#define VPIF_CH_SDR_FMT_BIT (4) -#define VPIF_CH_HANC_EN_BIT (8) -#define VPIF_CH_VANC_EN_BIT (9) - -#define VPIF_CAPTURE_CH_NIP (10) -#define VPIF_DISPLAY_CH_NIP (11) - -#define VPIF_DISPLAY_PIX_EN_BIT (10) - -#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12) - -#define VPIF_CH_FID_POLARITY_BIT (15) -#define VPIF_CH_V_VALID_POLARITY_BIT (14) -#define VPIF_CH_H_VALID_POLARITY_BIT (13) -#define VPIF_CH_DATA_WIDTH_BIT (28) - -#define VPIF_CH_CLK_EDGE_CTRL_BIT (31) - -/* Mask various length */ -#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0) -#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0) -#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0) -#define VPIF_CH_LEN_SHIFT (16) - -/* VPIF masks for registers */ -#define VPIF_REQ_SIZE_MASK (0x1ff) - -/* bit posotion of interrupt vpif_ch_intr register */ -#define VPIF_INTEN_FRAME_CH0 (0x00000001) -#define VPIF_INTEN_FRAME_CH1 (0x00000002) -#define VPIF_INTEN_FRAME_CH2 (0x00000004) -#define VPIF_INTEN_FRAME_CH3 (0x00000008) - -/* bit position of clock and channel enable in vpif_chn_ctrl register */ - -#define VPIF_CH0_CLK_EN (0x00000002) -#define VPIF_CH0_EN (0x00000001) -#define VPIF_CH1_CLK_EN (0x00000002) -#define VPIF_CH1_EN (0x00000001) -#define VPIF_CH2_CLK_EN (0x00000002) -#define VPIF_CH2_EN (0x00000001) -#define VPIF_CH3_CLK_EN (0x00000002) -#define VPIF_CH3_EN (0x00000001) -#define VPIF_CH_CLK_EN (0x00000002) -#define VPIF_CH_EN (0x00000001) - -#define VPIF_INT_TOP (0x00) -#define VPIF_INT_BOTTOM (0x01) -#define VPIF_INT_BOTH (0x02) - -#define VPIF_CH0_INT_CTRL_SHIFT (6) -#define VPIF_CH1_INT_CTRL_SHIFT (6) -#define VPIF_CH2_INT_CTRL_SHIFT (6) -#define VPIF_CH3_INT_CTRL_SHIFT (6) -#define VPIF_CH_INT_CTRL_SHIFT (6) - -/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ -#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) - -/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ -#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL)) - -/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ -#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL)) - -/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ -#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\ - (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL)) - -#define VPIF_CH_FID_MASK (0x20) -#define VPIF_CH_FID_SHIFT (5) - -#define VPIF_NTSC_VBI_START_FIELD0 (1) -#define VPIF_NTSC_VBI_START_FIELD1 (263) -#define VPIF_PAL_VBI_START_FIELD0 (624) -#define VPIF_PAL_VBI_START_FIELD1 (311) - -#define VPIF_NTSC_HBI_START_FIELD0 (1) -#define VPIF_NTSC_HBI_START_FIELD1 (263) -#define VPIF_PAL_HBI_START_FIELD0 (624) -#define VPIF_PAL_HBI_START_FIELD1 (311) - -#define VPIF_NTSC_VBI_COUNT_FIELD0 (20) -#define VPIF_NTSC_VBI_COUNT_FIELD1 (19) -#define VPIF_PAL_VBI_COUNT_FIELD0 (24) -#define VPIF_PAL_VBI_COUNT_FIELD1 (25) - -#define VPIF_NTSC_HBI_COUNT_FIELD0 (263) -#define VPIF_NTSC_HBI_COUNT_FIELD1 (262) -#define VPIF_PAL_HBI_COUNT_FIELD0 (312) -#define VPIF_PAL_HBI_COUNT_FIELD1 (313) - -#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720) -#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720) -#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268) -#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280) - -#define VPIF_CH_VANC_EN (0x20) -#define VPIF_DMA_REQ_SIZE (0x080) -#define VPIF_EMULATION_DISABLE (0x01) - -extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS]; - -/* inline function to enable/disable channel0 */ -static inline void enable_channel0(int enable) -{ - if (enable) - regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL); - else - regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL); -} - -/* inline function to enable/disable channel1 */ -static inline void enable_channel1(int enable) -{ - if (enable) - regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL); - else - regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL); -} - -/* inline function to enable interrupt for channel0 */ -static inline void channel0_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to enable interrupt for channel1 */ -static inline void channel1_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to set buffer addresses in case of Y/C non mux mode */ -static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); -} - -/* inline function to set buffer addresses in VPIF registers for video data */ -static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); -} - -static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - - regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); -} - -static inline void ch0_set_vbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC); - regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC); -} - -static inline void ch0_set_hbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC); - regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC); -} - -static inline void ch1_set_vbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC); - regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC); -} - -static inline void ch1_set_hbi_addr(unsigned long top_vbi, - unsigned long btm_vbi, unsigned long a, unsigned long b) -{ - regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC); - regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC); -} - -/* Inline function to enable raw vbi in the given channel */ -static inline void disable_raw_feature(u8 channel_id, u8 index) -{ - u32 ctrl_reg; - if (0 == channel_id) - ctrl_reg = VPIF_CH0_CTRL; - else - ctrl_reg = VPIF_CH1_CTRL; - - if (1 == index) - vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); - else - vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); -} - -static inline void enable_raw_feature(u8 channel_id, u8 index) -{ - u32 ctrl_reg; - if (0 == channel_id) - ctrl_reg = VPIF_CH0_CTRL; - else - ctrl_reg = VPIF_CH1_CTRL; - - if (1 == index) - vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); - else - vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); -} - -/* inline function to enable/disable channel2 */ -static inline void enable_channel2(int enable) -{ - if (enable) { - regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); - regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL); - } else { - regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); - regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL); - } -} - -/* inline function to enable/disable channel3 */ -static inline void enable_channel3(int enable) -{ - if (enable) { - regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); - regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL); - } else { - regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); - regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL); - } -} - -/* inline function to enable interrupt for channel2 */ -static inline void channel2_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to enable interrupt for channel3 */ -static inline void channel3_intr_enable(int enable) -{ - unsigned long flags; - - spin_lock_irqsave(&vpif_lock, flags); - - if (enable) { - regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); - - regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), - VPIF_INTEN_SET); - } else { - regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN); - regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), - VPIF_INTEN_SET); - } - spin_unlock_irqrestore(&vpif_lock, flags); -} - -/* inline function to enable raw vbi data for channel2 */ -static inline void channel2_raw_enable(int enable, u8 index) -{ - u32 mask; - - if (1 == index) - mask = VPIF_CH_VANC_EN_BIT; - else - mask = VPIF_CH_HANC_EN_BIT; - - if (enable) - vpif_set_bit(VPIF_CH2_CTRL, mask); - else - vpif_clr_bit(VPIF_CH2_CTRL, mask); -} - -/* inline function to enable raw vbi data for channel3*/ -static inline void channel3_raw_enable(int enable, u8 index) -{ - u32 mask; - - if (1 == index) - mask = VPIF_CH_VANC_EN_BIT; - else - mask = VPIF_CH_HANC_EN_BIT; - - if (enable) - vpif_set_bit(VPIF_CH3_CTRL, mask); - else - vpif_clr_bit(VPIF_CH3_CTRL, mask); -} - -/* inline function to set buffer addresses in case of Y/C non mux mode */ -static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); -} - -/* inline function to set buffer addresses in VPIF registers for video data */ -static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); -} - -static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); - regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); - regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); - regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); -} - -/* inline function to set buffer addresses in VPIF registers for vbi data */ -static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); - regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); -} - -static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) -{ - regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); - regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); -} - -#define VPIF_MAX_NAME (30) - -/* This structure will store size parameters as per the mode selected by user */ -struct vpif_channel_config_params { - char name[VPIF_MAX_NAME]; /* Name of the mode */ - u16 width; /* Indicates width of the image */ - u16 height; /* Indicates height of the image */ - u8 fps; - u8 frm_fmt; /* Indicates whether this is interlaced - * or progressive format */ - u8 ycmux_mode; /* Indicates whether this mode requires - * single or two channels */ - u16 eav2sav; /* length of sav 2 eav */ - u16 sav2eav; /* length of sav 2 eav */ - u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ - u16 vsize; /* Vertical size of the image */ - u8 capture_format; /* Indicates whether capture format - * is in BT or in CCD/CMOS */ - u8 vbi_supported; /* Indicates whether this mode - * supports capturing vbi or not */ - u8 hd_sd; - v4l2_std_id stdid; -}; - -struct vpif_video_params; -struct vpif_params; -struct vpif_vbi_params; - -int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id); -void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, - u8 channel_id); -int vpif_channel_getfid(u8 channel_id); - -enum data_size { - _8BITS = 0, - _10BITS, - _12BITS, -}; - -/* Structure for vpif parameters for raw vbi data */ -struct vpif_vbi_params { - __u32 hstart0; /* Horizontal start of raw vbi data for first field */ - __u32 vstart0; /* Vertical start of raw vbi data for first field */ - __u32 hsize0; /* Horizontal size of raw vbi data for first field */ - __u32 vsize0; /* Vertical size of raw vbi data for first field */ - __u32 hstart1; /* Horizontal start of raw vbi data for second field */ - __u32 vstart1; /* Vertical start of raw vbi data for second field */ - __u32 hsize1; /* Horizontal size of raw vbi data for second field */ - __u32 vsize1; /* Vertical size of raw vbi data for second field */ -}; - -/* structure for vpif parameters */ -struct vpif_video_params { - __u8 storage_mode; /* Indicates field or frame mode */ - unsigned long hpitch; - v4l2_std_id stdid; -}; - -struct vpif_params { - struct vpif_interface iface; - struct vpif_video_params video_params; - struct vpif_channel_config_params std_info; - union param { - struct vpif_vbi_params vbi_params; - enum data_size data_sz; - } params; -}; - -#endif /* End of #ifndef VPIF_H */ - diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c deleted file mode 100644 index 7813072..0000000 --- a/drivers/media/video/davinci/vpif_capture.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * Copyright (C) 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 - * - * TODO : add support for VBI & HBI data service - * add static buffer allocation - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vpif_capture.h" -#include "vpif.h" - -MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); -MODULE_LICENSE("GPL"); - -#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) -#define vpif_dbg(level, debug, fmt, arg...) \ - v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) - -static int debug = 1; -static u32 ch0_numbuffers = 3; -static u32 ch1_numbuffers = 3; -static u32 ch0_bufsize = 1920 * 1080 * 2; -static u32 ch1_bufsize = 720 * 576 * 2; - -module_param(debug, int, 0644); -module_param(ch0_numbuffers, uint, S_IRUGO); -module_param(ch1_numbuffers, uint, S_IRUGO); -module_param(ch0_bufsize, uint, S_IRUGO); -module_param(ch1_bufsize, uint, S_IRUGO); - -MODULE_PARM_DESC(debug, "Debug level 0-1"); -MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)"); -MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)"); -MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)"); -MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)"); - -static struct vpif_config_params config_params = { - .min_numbuffers = 3, - .numbuffers[0] = 3, - .numbuffers[1] = 3, - .min_bufsize[0] = 720 * 480 * 2, - .min_bufsize[1] = 720 * 480 * 2, - .channel_bufsize[0] = 1920 * 1080 * 2, - .channel_bufsize[1] = 720 * 576 * 2, -}; - -/* global variables */ -static struct vpif_device vpif_obj = { {NULL} }; -static struct device *vpif_dev; - -/** - * ch_params: video standard configuration parameters for vpif - */ -static const struct vpif_channel_config_params ch_params[] = { - { - "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, - 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, - }, - { - "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, - 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, - }, -}; - -/** - * vpif_uservirt_to_phys : translate user/virtual address to phy address - * @virtp: user/virtual address - * - * This inline function is used to convert user space virtual address to - * physical address. - */ -static inline u32 vpif_uservirt_to_phys(u32 virtp) -{ - unsigned long physp = 0; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - vma = find_vma(mm, virtp); - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) - physp = virt_to_phys((void *)virtp); - else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) - /** - * this will catch, kernel-allocated, mmaped-to-usermode - * addresses - */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, - virtp, nr_pages, 1, 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - else { - vpif_err("get_user_pages failed\n"); - return 0; - } - } - return physp; -} - -/** - * buffer_prepare : callback function for buffer prepare - * @q : buffer queue ptr - * @vb: ptr to video buffer - * @field: field info - * - * This is the callback function for buffer prepare when videobuf_qbuf() - * function is called. The buffer is prepared and user space virtual address - * or user address is converted into physical address - */ -static int vpif_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - unsigned long addr; - - - vpif_dbg(2, debug, "vpif_buffer_prepare\n"); - - common = &ch->common[VPIF_VIDEO_INDEX]; - - /* 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; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - /** - * if user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (0 == vb->baddr) { - vpif_dbg(1, debug, "buffer address is 0\n"); - return -EINVAL; - - } - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!IS_ALIGNED(vb->boff, 8)) - goto exit; - } - - addr = vb->boff; - if (q->streaming) { - if (!IS_ALIGNED((addr + common->ytop_off), 8) || - !IS_ALIGNED((addr + common->ybtm_off), 8) || - !IS_ALIGNED((addr + common->ctop_off), 8) || - !IS_ALIGNED((addr + common->cbtm_off), 8)) - goto exit; - } - return 0; -exit: - vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n"); - return -EINVAL; -} - -/** - * vpif_buffer_setup : Callback function for buffer setup. - * @q: buffer queue ptr - * @count: number of buffers - * @size: size of the buffer - * - * This callback function is called when reqbuf() is called to adjust - * the buffer count and buffer size - */ -static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_buffer_setup\n"); - - /* If memory type is not mmap, return */ - if (V4L2_MEMORY_MMAP != common->memory) - return 0; - - /* Calculate the size of the buffer */ - *size = config_params.channel_bufsize[ch->channel_id]; - - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - return 0; -} - -/** - * vpif_buffer_queue : Callback function to add buffer to DMA queue - * @q: ptr to videobuf_queue - * @vb: ptr to videobuf_buffer - */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; -} - -/** - * vpif_buffer_release : Callback function to free buffer - * @q: buffer queue ptr - * @vb: ptr to video buffer - * - * This function is called from the videobuf layer to free memory - * allocated to the buffers - */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpif_buffer_setup, - .buf_prepare = vpif_buffer_prepare, - .buf_queue = vpif_buffer_queue, - .buf_release = vpif_buffer_release, -}; - -static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = - { {1, 1} }; - -/** - * vpif_process_buffer_complete: process a completed buffer - * @common: ptr to common channel object - * - * This function time stamp the buffer and mark it as DONE. It also - * wake up any process waiting on the QUEUE and set the next buffer - * as current - */ -static void vpif_process_buffer_complete(struct common_obj *common) -{ - do_gettimeofday(&common->cur_frm->ts); - common->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&common->cur_frm->done); - /* Make curFrm pointing to nextFrm */ - common->cur_frm = common->next_frm; -} - -/** - * vpif_schedule_next_buffer: set next buffer address for capture - * @common : ptr to common channel object - * - * This function will get next buffer from the dma queue and - * set the buffer address in the vpif register for capture. - * the buffer is marked active - */ -static void vpif_schedule_next_buffer(struct common_obj *common) -{ - unsigned long addr = 0; - - common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); - common->next_frm->state = VIDEOBUF_ACTIVE; - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->next_frm->boff; - else - addr = videobuf_to_dma_contig(common->next_frm); - - /* Set top and bottom field addresses in VPIF registers */ - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); -} - -/** - * vpif_channel_isr : ISR handler for vpif capture - * @irq: irq number - * @dev_id: dev_id ptr - * - * It changes status of the captured buffer, takes next buffer from the queue - * and sets its address in VPIF registers - */ -static irqreturn_t vpif_channel_isr(int irq, void *dev_id) -{ - struct vpif_device *dev = &vpif_obj; - struct common_obj *common; - struct channel_obj *ch; - enum v4l2_field field; - int channel_id = 0; - int fid = -1, i; - - channel_id = *(int *)(dev_id); - ch = dev->dev[channel_id]; - - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; - - for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { - common = &ch->common[i]; - /* skip If streaming is not started in this channel */ - if (0 == common->started) - continue; - - /* Check the field format */ - if (1 == ch->vpifparams.std_info.frm_fmt) { - /* Progressive mode */ - if (list_empty(&common->dma_queue)) - continue; - - if (!channel_first_int[i][channel_id]) - vpif_process_buffer_complete(common); - - channel_first_int[i][channel_id] = 0; - - vpif_schedule_next_buffer(common); - - - channel_first_int[i][channel_id] = 0; - } else { - /** - * Interlaced mode. If it is first interrupt, ignore - * it - */ - if (channel_first_int[i][channel_id]) { - channel_first_int[i][channel_id] = 0; - continue; - } - if (0 == i) { - ch->field_id ^= 1; - /* Get field id from VPIF registers */ - fid = vpif_channel_getfid(ch->channel_id); - if (fid != ch->field_id) { - /** - * If field id does not match stored - * field id, make them in sync - */ - if (0 == fid) - ch->field_id = fid; - return IRQ_HANDLED; - } - } - /* device field id and local field id are in sync */ - if (0 == fid) { - /* this is even field */ - if (common->cur_frm == common->next_frm) - continue; - - /* mark the current buffer as done */ - vpif_process_buffer_complete(common); - } else if (1 == fid) { - /* odd field */ - if (list_empty(&common->dma_queue) || - (common->cur_frm != common->next_frm)) - continue; - - vpif_schedule_next_buffer(common); - } - } - } - return IRQ_HANDLED; -} - -/** - * vpif_update_std_info() - update standard related info - * @ch: ptr to channel object - * - * For a given standard selected by application, update values - * in the device data structures - */ -static int vpif_update_std_info(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct vpif_params *vpifparams = &ch->vpifparams; - const struct vpif_channel_config_params *config; - struct vpif_channel_config_params *std_info; - struct video_obj *vid_ch = &ch->video; - int index; - - vpif_dbg(2, debug, "vpif_update_std_info\n"); - - std_info = &vpifparams->std_info; - - for (index = 0; index < ARRAY_SIZE(ch_params); index++) { - config = &ch_params[index]; - if (config->stdid & vid_ch->stdid) { - memcpy(std_info, config, sizeof(*config)); - break; - } - } - - /* standard not found */ - if (index == ARRAY_SIZE(ch_params)) - return -EINVAL; - - common->fmt.fmt.pix.width = std_info->width; - common->width = std_info->width; - common->fmt.fmt.pix.height = std_info->height; - common->height = std_info->height; - common->fmt.fmt.pix.bytesperline = std_info->width; - vpifparams->video_params.hpitch = std_info->width; - vpifparams->video_params.storage_mode = std_info->frm_fmt; - return 0; -} - -/** - * vpif_calculate_offsets : This function calculates buffers offsets - * @ch : ptr to channel object - * - * This function calculates buffer offsets for Y and C in the top and - * bottom field - */ -static void vpif_calculate_offsets(struct channel_obj *ch) -{ - unsigned int hpitch, vpitch, sizeimage; - struct video_obj *vid_ch = &(ch->video); - struct vpif_params *vpifparams = &ch->vpifparams; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - enum v4l2_field field = common->fmt.fmt.pix.field; - - vpif_dbg(2, debug, "vpif_calculate_offsets\n"); - - if (V4L2_FIELD_ANY == field) { - if (vpifparams->std_info.frm_fmt) - vid_ch->buf_field = V4L2_FIELD_NONE; - else - vid_ch->buf_field = V4L2_FIELD_INTERLACED; - } else - vid_ch->buf_field = common->fmt.fmt.pix.field; - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = common->fmt.fmt.pix.sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); - - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { - /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ - common->ytop_off = 0; - common->ybtm_off = hpitch; - common->ctop_off = sizeimage / 2; - common->cbtm_off = sizeimage / 2 + hpitch; - } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { - /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ - common->ytop_off = 0; - common->ybtm_off = sizeimage / 4; - common->ctop_off = sizeimage / 2; - common->cbtm_off = common->ctop_off + sizeimage / 4; - } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { - /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ - common->ybtm_off = 0; - common->ytop_off = sizeimage / 4; - common->cbtm_off = sizeimage / 2; - common->ctop_off = common->cbtm_off + sizeimage / 4; - } - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) - vpifparams->video_params.storage_mode = 1; - else - vpifparams->video_params.storage_mode = 0; - - if (1 == vpifparams->std_info.frm_fmt) - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - else { - if ((field == V4L2_FIELD_ANY) - || (field == V4L2_FIELD_INTERLACED)) - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline * 2; - else - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - } - - ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid; -} - -/** - * vpif_config_format: configure default frame format in the device - * ch : ptr to channel object - */ -static void vpif_config_format(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_config_format\n"); - - common->fmt.fmt.pix.field = V4L2_FIELD_ANY; - if (config_params.numbuffers[ch->channel_id] == 0) - common->memory = V4L2_MEMORY_USERPTR; - else - common->memory = V4L2_MEMORY_MMAP; - - common->fmt.fmt.pix.sizeimage - = config_params.channel_bufsize[ch->channel_id]; - - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) - common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; - else - common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; - common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -} - -/** - * vpif_get_default_field() - Get default field type based on interface - * @vpif_params - ptr to vpif params - */ -static inline enum v4l2_field vpif_get_default_field( - struct vpif_interface *iface) -{ - return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : - V4L2_FIELD_INTERLACED; -} - -/** - * vpif_check_format() - check given pixel format for compatibility - * @ch - channel ptr - * @pixfmt - Given pixel format - * @update - update the values as per hardware requirement - * - * Check the application pixel format for S_FMT and update the input - * values as per hardware limits for TRY_FMT. The default pixel and - * field format is selected based on interface type. - */ -static int vpif_check_format(struct channel_obj *ch, - struct v4l2_pix_format *pixfmt, - int update) -{ - struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); - struct vpif_params *vpif_params = &ch->vpifparams; - enum v4l2_field field = pixfmt->field; - u32 sizeimage, hpitch, vpitch; - int ret = -EINVAL; - - vpif_dbg(2, debug, "vpif_check_format\n"); - /** - * first check for the pixel format. If if_type is Raw bayer, - * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only - * V4L2_PIX_FMT_YUV422P is supported - */ - if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) { - if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) { - if (!update) { - vpif_dbg(2, debug, "invalid pix format\n"); - goto exit; - } - pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8; - } - } else { - if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) { - if (!update) { - vpif_dbg(2, debug, "invalid pixel format\n"); - goto exit; - } - pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P; - } - } - - if (!(VPIF_VALID_FIELD(field))) { - if (!update) { - vpif_dbg(2, debug, "invalid field format\n"); - goto exit; - } - /** - * By default use FIELD_NONE for RAW Bayer capture - * and FIELD_INTERLACED for other interfaces - */ - field = vpif_get_default_field(&vpif_params->iface); - } else if (field == V4L2_FIELD_ANY) - /* unsupported field. Use default */ - field = vpif_get_default_field(&vpif_params->iface); - - /* validate the hpitch */ - hpitch = pixfmt->bytesperline; - if (hpitch < vpif_params->std_info.width) { - if (!update) { - vpif_dbg(2, debug, "invalid hpitch\n"); - goto exit; - } - hpitch = vpif_params->std_info.width; - } - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - vpitch = sizeimage / (hpitch * 2); - - /* validate the vpitch */ - if (vpitch < vpif_params->std_info.height) { - if (!update) { - vpif_dbg(2, debug, "Invalid vpitch\n"); - goto exit; - } - vpitch = vpif_params->std_info.height; - } - - /* Check for 8 byte alignment */ - if (!ALIGN(hpitch, 8)) { - if (!update) { - vpif_dbg(2, debug, "invalid pitch alignment\n"); - goto exit; - } - /* adjust to next 8 byte boundary */ - hpitch = (((hpitch + 7) / 8) * 8); - } - /* if update is set, modify the bytesperline and sizeimage */ - if (update) { - pixfmt->bytesperline = hpitch; - pixfmt->sizeimage = hpitch * vpitch * 2; - } - /** - * Image width and height is always based on current standard width and - * height - */ - pixfmt->width = common->fmt.fmt.pix.width; - pixfmt->height = common->fmt.fmt.pix.height; - return 0; -exit: - return ret; -} - -/** - * vpif_config_addr() - function to configure buffer address in vpif - * @ch - channel ptr - * @muxmode - channel mux mode - */ -static void vpif_config_addr(struct channel_obj *ch, int muxmode) -{ - struct common_obj *common; - - vpif_dbg(2, debug, "vpif_config_addr\n"); - - common = &(ch->common[VPIF_VIDEO_INDEX]); - - if (VPIF_CHANNEL1_VIDEO == ch->channel_id) - common->set_addr = ch1_set_videobuf_addr; - else if (2 == muxmode) - common->set_addr = ch0_set_videobuf_addr_yc_nmux; - else - common->set_addr = ch0_set_videobuf_addr; -} - -/** - * vpfe_mmap : It is used to map kernel space buffers into user spaces - * @filep: file pointer - * @vma: ptr to vm_area_struct - */ -static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) -{ - /* Get the channel object and file handle object */ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); - - vpif_dbg(2, debug, "vpif_mmap\n"); - - return videobuf_mmap_mapper(&common->buffer_queue, vma); -} - -/** - * vpif_poll: It is used for select/poll system call - * @filep: file pointer - * @wait: poll table to wait - */ -static unsigned int vpif_poll(struct file *filep, poll_table * wait) -{ - int err = 0; - struct vpif_fh *fh = filep->private_data; - struct channel_obj *channel = fh->channel; - struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]); - - vpif_dbg(2, debug, "vpif_poll\n"); - - if (common->started) - err = videobuf_poll_stream(filep, &common->buffer_queue, wait); - - return 0; -} - -/** - * vpif_open : vpif open handler - * @filep: file ptr - * - * It creates object of file handle structure and stores it in private_data - * member of filepointer - */ -static int vpif_open(struct file *filep) -{ - struct vpif_capture_config *config = vpif_dev->platform_data; - struct video_device *vdev = video_devdata(filep); - struct common_obj *common; - struct video_obj *vid_ch; - struct channel_obj *ch; - struct vpif_fh *fh; - int i, ret = 0; - - vpif_dbg(2, debug, "vpif_open\n"); - - ch = video_get_drvdata(vdev); - - vid_ch = &ch->video; - common = &ch->common[VPIF_VIDEO_INDEX]; - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (NULL == ch->curr_subdev_info) { - /** - * search through the sub device to see a registered - * sub device and make it as current sub device - */ - for (i = 0; i < config->subdev_count; i++) { - if (vpif_obj.sd[i]) { - /* the sub device is registered */ - ch->curr_subdev_info = &config->subdev_info[i]; - /* make first input as the current input */ - vid_ch->input_idx = 0; - break; - } - } - if (i == config->subdev_count) { - vpif_err("No sub device registered\n"); - ret = -ENOENT; - goto exit; - } - } - - /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL); - if (NULL == fh) { - vpif_err("unable to allocate memory for file handle object\n"); - ret = -ENOMEM; - goto exit; - } - - /* store pointer to fh in private_data member of filep */ - filep->private_data = fh; - fh->channel = ch; - fh->initialized = 0; - /* If decoder is not initialized. initialize it */ - if (!ch->initialized) { - fh->initialized = 1; - ch->initialized = 1; - memset(&(ch->vpifparams), 0, sizeof(struct vpif_params)); - } - /* Increment channel usrs counter */ - ch->usrs++; - /* Set io_allowed member to false */ - fh->io_allowed[VPIF_VIDEO_INDEX] = 0; - /* Initialize priority of this instance to default priority */ - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&ch->prio, &fh->prio); -exit: - mutex_unlock(&common->lock); - return ret; -} - -/** - * vpif_release : function to clean up file close - * @filep: file pointer - * - * This function deletes buffer queue, frees the buffers and the vpfe file - * handle - */ -static int vpif_release(struct file *filep) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - - vpif_dbg(2, debug, "vpif_release\n"); - - common = &ch->common[VPIF_VIDEO_INDEX]; - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - /* if this instance is doing IO */ - if (fh->io_allowed[VPIF_VIDEO_INDEX]) { - /* Reset io_usrs member of channel object */ - common->io_usrs = 0; - /* Disable channel as per its device type and channel id */ - if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { - enable_channel0(0); - channel0_intr_enable(0); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel1(0); - channel1_intr_enable(0); - } - common->started = 0; - /* Free buffers allocated */ - videobuf_queue_cancel(&common->buffer_queue); - videobuf_mmap_free(&common->buffer_queue); - } - - /* Decrement channel usrs counter */ - ch->usrs--; - - /* unlock mutex on channel object */ - mutex_unlock(&common->lock); - - /* Close the priority */ - v4l2_prio_close(&ch->prio, &fh->prio); - - if (fh->initialized) - ch->initialized = 0; - - filep->private_data = NULL; - kfree(fh); - return 0; -} - -/** - * vpif_reqbufs() - request buffer handler - * @file: file ptr - * @priv: file handle - * @reqbuf: request buffer structure ptr - */ -static int vpif_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbuf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - u8 index = 0; - int ret = 0; - - vpif_dbg(2, debug, "vpif_reqbufs\n"); - - /** - * This file handle has not initialized the channel, - * It is not allowed to do settings - */ - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) - || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) - return -EINVAL; - - index = VPIF_VIDEO_INDEX; - - common = &ch->common[index]; - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (0 != common->io_usrs) { - ret = -EBUSY; - goto reqbuf_exit; - } - - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, - common->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), fh); - - /* Set io allowed member of file handle to TRUE */ - fh->io_allowed[index] = 1; - /* Increment io usrs member of channel object to 1 */ - common->io_usrs = 1; - /* Store type of memory requested in channel object */ - common->memory = reqbuf->memory; - INIT_LIST_HEAD(&common->dma_queue); - - /* Allocate buffers */ - ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); - -reqbuf_exit: - mutex_unlock(&common->lock); - return ret; -} - -/** - * vpif_querybuf() - query buffer handler - * @file: file ptr - * @priv: file handle - * @buf: v4l2 buffer structure ptr - */ -static int vpif_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_querybuf\n"); - - if (common->fmt.type != buf->type) - return -EINVAL; - - if (common->memory != V4L2_MEMORY_MMAP) { - vpif_dbg(1, debug, "Invalid memory\n"); - return -EINVAL; - } - - return videobuf_querybuf(&common->buffer_queue, buf); -} - -/** - * vpif_qbuf() - query buffer handler - * @file: file ptr - * @priv: file handle - * @buf: v4l2 buffer structure ptr - */ -static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_buffer tbuf = *buf; - struct videobuf_buffer *buf1; - unsigned long addr = 0; - unsigned long flags; - int ret = 0; - - vpif_dbg(2, debug, "vpif_qbuf\n"); - - if (common->fmt.type != tbuf.type) { - vpif_err("invalid buffer type\n"); - return -EINVAL; - } - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh io not allowed \n"); - return -EACCES; - } - - if (!(list_empty(&common->dma_queue)) || - (common->cur_frm != common->next_frm) || - !common->started || - (common->started && (0 == ch->field_id))) - return videobuf_qbuf(&common->buffer_queue, buf); - - /* bufferqueue is empty store buffer address in VPIF registers */ - mutex_lock(&common->buffer_queue.vb_lock); - buf1 = common->buffer_queue.bufs[tbuf.index]; - - if ((buf1->state == VIDEOBUF_QUEUED) || - (buf1->state == VIDEOBUF_ACTIVE)) { - vpif_err("invalid state\n"); - goto qbuf_exit; - } - - switch (buf1->memory) { - case V4L2_MEMORY_MMAP: - if (buf1->baddr == 0) - goto qbuf_exit; - break; - - case V4L2_MEMORY_USERPTR: - if (tbuf.length < buf1->bsize) - goto qbuf_exit; - - if ((VIDEOBUF_NEEDS_INIT != buf1->state) - && (buf1->baddr != tbuf.m.userptr)) - vpif_buffer_release(&common->buffer_queue, buf1); - buf1->baddr = tbuf.m.userptr; - break; - - default: - goto qbuf_exit; - } - - local_irq_save(flags); - ret = vpif_buffer_prepare(&common->buffer_queue, buf1, - common->buffer_queue.field); - if (ret < 0) { - local_irq_restore(flags); - goto qbuf_exit; - } - - buf1->state = VIDEOBUF_ACTIVE; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = buf1->boff; - else - addr = videobuf_to_dma_contig(buf1); - - common->next_frm = buf1; - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); - - local_irq_restore(flags); - list_add_tail(&buf1->stream, &common->buffer_queue.stream); - mutex_unlock(&common->buffer_queue.vb_lock); - return 0; - -qbuf_exit: - mutex_unlock(&common->buffer_queue.vb_lock); - return -EINVAL; -} - -/** - * vpif_dqbuf() - query buffer handler - * @file: file ptr - * @priv: file handle - * @buf: v4l2 buffer structure ptr - */ -static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - vpif_dbg(2, debug, "vpif_dqbuf\n"); - - return videobuf_dqbuf(&common->buffer_queue, buf, - file->f_flags & O_NONBLOCK); -} - -/** - * vpif_streamon() - streamon handler - * @file: file ptr - * @priv: file handle - * @buftype: v4l2 buffer type - */ -static int vpif_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - - struct vpif_capture_config *config = vpif_dev->platform_data; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; - struct vpif_params *vpif; - unsigned long addr = 0; - int ret = 0; - - vpif_dbg(2, debug, "vpif_streamon\n"); - - vpif = &ch->vpifparams; - - if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - vpif_dbg(1, debug, "buffer type not supported\n"); - return -EINVAL; - } - - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_dbg(1, debug, "io not allowed\n"); - return -EACCES; - } - - /* If Streaming is already started, return error */ - if (common->started) { - vpif_dbg(1, debug, "channel->started\n"); - return -EBUSY; - } - - if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && - oth_ch->common[VPIF_VIDEO_INDEX].started && - vpif->std_info.ycmux_mode == 0) || - ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && - (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { - vpif_dbg(1, debug, "other channel is being used\n"); - return -EBUSY; - } - - ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); - if (ret) - return ret; - - /* Enable streamon on the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 1); - - if (ret && (ret != -ENOIOCTLCMD)) { - vpif_dbg(1, debug, "stream on failed in subdev\n"); - return ret; - } - - /* Call videobuf_streamon to start streaming in videobuf */ - ret = videobuf_streamon(&common->buffer_queue); - if (ret) { - vpif_dbg(1, debug, "videobuf_streamon\n"); - return ret; - } - - if (mutex_lock_interruptible(&common->lock)) { - ret = -ERESTARTSYS; - goto streamoff_exit; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_dbg(1, debug, "buffer queue is empty\n"); - ret = -EIO; - goto exit; - } - - /* Get the next frame from the buffer queue */ - common->cur_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - common->next_frm = common->cur_frm; - - /* Remove buffer from the buffer queue */ - list_del(&common->cur_frm->queue); - /* Mark state of the current frame to active */ - common->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - ch->field_id = 0; - common->started = 1; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->cur_frm->boff; - else - addr = videobuf_to_dma_contig(common->cur_frm); - - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((vpif->std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && - (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || - (!vpif->std_info.frm_fmt && - (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_dbg(1, debug, "conflict in field format and std format\n"); - ret = -EINVAL; - goto exit; - } - - /* configure 1 or 2 channel mode */ - ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - goto exit; - } - - /* Call vpif_set_params function to set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set video params\n"); - goto exit; - } - - common->started = ret; - vpif_config_addr(ch, ret); - - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); - - /** - * Set interrupt for both the fields in VPIF Register enable channel in - * VPIF register - */ - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { - channel0_intr_assert(); - channel0_intr_enable(1); - enable_channel0(1); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (common->started == 2)) { - channel1_intr_assert(); - channel1_intr_enable(1); - enable_channel1(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - mutex_unlock(&common->lock); - return ret; - -exit: - mutex_unlock(&common->lock); -streamoff_exit: - ret = videobuf_streamoff(&common->buffer_queue); - return ret; -} - -/** - * vpif_streamoff() - streamoff handler - * @file: file ptr - * @priv: file handle - * @buftype: v4l2 buffer type - */ -static int vpif_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret; - - vpif_dbg(2, debug, "vpif_streamoff\n"); - - if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - vpif_dbg(1, debug, "buffer type not supported\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_dbg(1, debug, "io not allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!common->started) { - vpif_dbg(1, debug, "channel->started\n"); - return -EINVAL; - } - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - /* disable channel */ - if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { - enable_channel0(0); - channel0_intr_enable(0); - } else { - enable_channel1(0); - channel1_intr_enable(0); - } - - common->started = 0; - - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 0); - - if (ret && (ret != -ENOIOCTLCMD)) - vpif_dbg(1, debug, "stream off failed in subdev\n"); - - mutex_unlock(&common->lock); - - return videobuf_streamoff(&common->buffer_queue); -} - -/** - * vpif_map_sub_device_to_input() - Maps sub device to input - * @ch - ptr to channel - * @config - ptr to capture configuration - * @input_index - Given input index from application - * @sub_device_index - index into sd table - * - * lookup the sub device information for a given input index. - * we report all the inputs to application. inputs table also - * has sub device name for the each input - */ -static struct vpif_subdev_info *vpif_map_sub_device_to_input( - struct channel_obj *ch, - struct vpif_capture_config *vpif_cfg, - int input_index, - int *sub_device_index) -{ - struct vpif_capture_chan_config *chan_cfg; - struct vpif_subdev_info *subdev_info = NULL; - const char *subdev_name = NULL; - int i; - - vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); - - chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - - /** - * search through the inputs to find the sub device supporting - * the input - */ - for (i = 0; i < chan_cfg->input_count; i++) { - /* For each sub device, loop through input */ - if (i == input_index) { - subdev_name = chan_cfg->inputs[i].subdev_name; - break; - } - } - - /* if reached maximum. return null */ - if (i == chan_cfg->input_count || (NULL == subdev_name)) - return subdev_info; - - /* loop through the sub device list to get the sub device info */ - for (i = 0; i < vpif_cfg->subdev_count; i++) { - subdev_info = &vpif_cfg->subdev_info[i]; - if (!strcmp(subdev_info->name, subdev_name)) - break; - } - - if (i == vpif_cfg->subdev_count) - return subdev_info; - - /* check if the sub device is registered */ - if (NULL == vpif_obj.sd[i]) - return NULL; - - *sub_device_index = i; - return subdev_info; -} - -/** - * vpif_querystd() - querystd handler - * @file: file ptr - * @priv: file handle - * @std_id: ptr to std id - * - * This function is called to detect standard at the selected input - */ -static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - vpif_dbg(2, debug, "vpif_querystd\n"); - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - /* Call querystd function of decoder device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - querystd, std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - - mutex_unlock(&common->lock); - return ret; -} - -/** - * vpif_g_std() - get STD handler - * @file: file ptr - * @priv: file handle - * @std_id: ptr to std id - */ -static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - vpif_dbg(2, debug, "vpif_g_std\n"); - - *std = ch->video.stdid; - return 0; -} - -/** - * vpif_s_std() - set STD handler - * @file: file ptr - * @priv: file handle - * @std_id: ptr to std id - */ -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - vpif_dbg(2, debug, "vpif_s_std\n"); - - if (common->started) { - vpif_err("streaming in progress\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, &fh->prio); - if (0 != ret) - return ret; - - fh->initialized = 1; - - /* Call encoder subdevice function to set the standard */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - ch->video.stdid = *std_id; - - /* Get the information about the standard */ - if (vpif_update_std_info(ch)) { - ret = -EINVAL; - vpif_err("Error getting the standard info\n"); - goto s_std_exit; - } - - /* Configure the default format information */ - vpif_config_format(ch); - - /* set standard in the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_std, *std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - -s_std_exit: - mutex_unlock(&common->lock); - return ret; -} - -/** - * vpif_enum_input() - ENUMINPUT handler - * @file: file ptr - * @priv: file handle - * @input: ptr to input structure - */ -static int vpif_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - - struct vpif_capture_config *config = vpif_dev->platform_data; - struct vpif_capture_chan_config *chan_cfg; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - chan_cfg = &config->chan_config[ch->channel_id]; - - if (input->index >= chan_cfg->input_count) { - vpif_dbg(1, debug, "Invalid input index\n"); - return -EINVAL; - } - - memcpy(input, &chan_cfg->inputs[input->index].input, - sizeof(*input)); - return 0; -} - -/** - * vpif_g_input() - Get INPUT handler - * @file: file ptr - * @priv: file handle - * @index: ptr to input index - */ -static int vpif_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *index = vid_ch->input_idx; - - return 0; -} - -/** - * vpif_s_input() - Set INPUT handler - * @file: file ptr - * @priv: file handle - * @index: input index - */ -static int vpif_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpif_capture_config *config = vpif_dev->platform_data; - struct vpif_capture_chan_config *chan_cfg; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - struct vpif_subdev_info *subdev_info; - int ret = 0, sd_index = 0; - u32 input = 0, output = 0; - - chan_cfg = &config->chan_config[ch->channel_id]; - - if (common->started) { - vpif_err("Streaming in progress\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, &fh->prio); - if (0 != ret) - return ret; - - fh->initialized = 1; - subdev_info = vpif_map_sub_device_to_input(ch, config, index, - &sd_index); - if (NULL == subdev_info) { - vpif_dbg(1, debug, - "couldn't lookup sub device for the input index\n"); - return -EINVAL; - } - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - /* first setup input path from sub device to vpif */ - if (config->setup_input_path) { - ret = config->setup_input_path(ch->channel_id, - subdev_info->name); - if (ret < 0) { - vpif_dbg(1, debug, "couldn't setup input path for the" - " sub device %s, for input index %d\n", - subdev_info->name, index); - goto exit; - } - } - - if (subdev_info->can_route) { - input = subdev_info->input; - output = subdev_info->output; - ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, - input, output, 0); - if (ret < 0) { - vpif_dbg(1, debug, "Failed to set input\n"); - goto exit; - } - } - vid_ch->input_idx = index; - ch->curr_subdev_info = subdev_info; - ch->curr_sd_index = sd_index; - /* copy interface parameters to vpif */ - ch->vpifparams.iface = subdev_info->vpif_if; - - /* update tvnorms from the sub device input info */ - ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - -exit: - mutex_unlock(&common->lock); - return ret; -} - -/** - * vpif_enum_fmt_vid_cap() - ENUM_FMT handler - * @file: file ptr - * @priv: file handle - * @index: input index - */ -static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - if (fmt->index != 0) { - vpif_dbg(1, debug, "Invalid format index\n"); - return -EINVAL; - } - - /* Fill in the information about format */ - if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); - fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; - } else { - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); - fmt->pixelformat = V4L2_PIX_FMT_YUV422P; - } - return 0; -} - -/** - * vpif_try_fmt_vid_cap() - TRY_FMT handler - * @file: file ptr - * @priv: file handle - * @fmt: ptr to v4l2 format structure - */ -static int vpif_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - return vpif_check_format(ch, pixfmt, 1); -} - - -/** - * vpif_g_fmt_vid_cap() - Set INPUT handler - * @file: file ptr - * @priv: file handle - * @fmt: ptr to v4l2 format structure - */ -static int vpif_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - /* Check the validity of the buffer type */ - if (common->fmt.type != fmt->type) - return -EINVAL; - - /* Fill in the information about format */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - *fmt = common->fmt; - mutex_unlock(&common->lock); - return 0; -} - -/** - * vpif_s_fmt_vid_cap() - Set FMT handler - * @file: file ptr - * @priv: file handle - * @fmt: ptr to v4l2 format structure - */ -static int vpif_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_pix_format *pixfmt; - int ret = 0; - - vpif_dbg(2, debug, "VIDIOC_S_FMT\n"); - - /* If streaming is started, return error */ - if (common->started) { - vpif_dbg(1, debug, "Streaming is started\n"); - return -EBUSY; - } - - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || - (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - } - - ret = v4l2_prio_check(&ch->prio, &fh->prio); - if (0 != ret) - return ret; - - fh->initialized = 1; - - pixfmt = &fmt->fmt.pix; - /* Check for valid field format */ - ret = vpif_check_format(ch, pixfmt, 0); - - if (ret) - return ret; - /* store the format in the channel object */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - common->fmt = *fmt; - mutex_unlock(&common->lock); - - return 0; -} - -/** - * vpif_querycap() - QUERYCAP handler - * @file: file ptr - * @priv: file handle - * @cap: ptr to v4l2_capability structure - */ -static int vpif_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpif_capture_config *config = vpif_dev->platform_data; - - cap->version = VPIF_CAPTURE_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); - strlcpy(cap->card, config->card_name, sizeof(cap->card)); - - return 0; -} - -/** - * vpif_g_priority() - get priority handler - * @file: file ptr - * @priv: file handle - * @prio: ptr to v4l2_priority structure - */ -static int vpif_g_priority(struct file *file, void *priv, - enum v4l2_priority *prio) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - *prio = v4l2_prio_max(&ch->prio); - - return 0; -} - -/** - * vpif_s_priority() - set priority handler - * @file: file ptr - * @priv: file handle - * @prio: ptr to v4l2_priority structure - */ -static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_prio_change(&ch->prio, &fh->prio, p); -} - -/** - * vpif_cropcap() - cropcap handler - * @file: file ptr - * @priv: file handle - * @crop: ptr to v4l2_cropcap structure - */ -static int vpif_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *crop) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type) - return -EINVAL; - - crop->bounds.left = 0; - crop->bounds.top = 0; - crop->bounds.height = common->height; - crop->bounds.width = common->width; - crop->defrect = crop->bounds; - return 0; -} - -/* vpif capture ioctl operations */ -static const struct v4l2_ioctl_ops vpif_ioctl_ops = { - .vidioc_querycap = vpif_querycap, - .vidioc_g_priority = vpif_g_priority, - .vidioc_s_priority = vpif_s_priority, - .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap, - .vidioc_enum_input = vpif_enum_input, - .vidioc_s_input = vpif_s_input, - .vidioc_g_input = vpif_g_input, - .vidioc_reqbufs = vpif_reqbufs, - .vidioc_querybuf = vpif_querybuf, - .vidioc_querystd = vpif_querystd, - .vidioc_s_std = vpif_s_std, - .vidioc_g_std = vpif_g_std, - .vidioc_qbuf = vpif_qbuf, - .vidioc_dqbuf = vpif_dqbuf, - .vidioc_streamon = vpif_streamon, - .vidioc_streamoff = vpif_streamoff, - .vidioc_cropcap = vpif_cropcap, -}; - -/* vpif file operations */ -static struct v4l2_file_operations vpif_fops = { - .owner = THIS_MODULE, - .open = vpif_open, - .release = vpif_release, - .ioctl = video_ioctl2, - .mmap = vpif_mmap, - .poll = vpif_poll -}; - -/* vpif video template */ -static struct video_device vpif_video_template = { - .name = "vpif", - .fops = &vpif_fops, - .minor = -1, - .ioctl_ops = &vpif_ioctl_ops, -}; - -/** - * initialize_vpif() - Initialize vpif data structures - * - * Allocate memory for data structures and initialize them - */ -static int initialize_vpif(void) -{ - int err = 0, i, j; - int free_channel_objects_index; - - /* Default number of buffers should be 3 */ - if ((ch0_numbuffers > 0) && - (ch0_numbuffers < config_params.min_numbuffers)) - ch0_numbuffers = config_params.min_numbuffers; - if ((ch1_numbuffers > 0) && - (ch1_numbuffers < config_params.min_numbuffers)) - ch1_numbuffers = config_params.min_numbuffers; - - /* Set buffer size to min buffers size if it is invalid */ - if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]) - ch0_bufsize = - config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]; - if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]) - ch1_bufsize = - config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]; - - config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers; - config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers; - if (ch0_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO] - = ch0_bufsize; - } - if (ch1_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO] - = ch1_bufsize; - } - - /* Allocate memory for six channel objects */ - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - vpif_obj.dev[i] = - kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL); - /* If memory allocation fails, return error */ - if (!vpif_obj.dev[i]) { - free_channel_objects_index = i; - err = -ENOMEM; - goto vpif_init_free_channel_objects; - } - } - return 0; - -vpif_init_free_channel_objects: - for (j = 0; j < free_channel_objects_index; j++) - kfree(vpif_obj.dev[j]); - return err; -} - -/** - * vpif_probe : This function probes the vpif capture driver - * @pdev: platform device pointer - * - * This creates device entries by register itself to the V4L2 driver and - * initializes fields of each channel objects - */ -static __init int vpif_probe(struct platform_device *pdev) -{ - struct vpif_subdev_info *subdevdata; - struct vpif_capture_config *config; - int i, j, k, m, q, err; - struct i2c_adapter *i2c_adap; - struct channel_obj *ch; - struct common_obj *common; - struct video_device *vfd; - struct resource *res; - int subdev_count; - - vpif_dev = &pdev->dev; - - err = initialize_vpif(); - if (err) { - v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); - return err; - } - - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { - for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Capture", - (void *)(&vpif_obj.dev[k]->channel_id))) { - err = -EBUSY; - i--; - goto vpif_int_err; - } - } - k++; - } - - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - for (j = 0; j < i; j++) { - ch = vpif_obj.dev[j]; - video_device_release(ch->video_dev); - } - err = -ENOMEM; - goto vpif_dev_alloc_err; - } - - /* Initialize field of video device */ - *vfd = vpif_video_template; - vfd->v4l2_dev = &vpif_obj.v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", - (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPIF_CAPTURE_VERSION_CODE) & 0xff); - /* Set video_dev to the video device */ - ch->video_dev = vfd; - } - - for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - ch->channel_id = j; - common = &(ch->common[VPIF_VIDEO_INDEX]); - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 1 : 0)); - if (err) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - - subdev_count = config->subdev_count; - vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); - if (err) { - v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - goto probe_subdev_out; - } - - for (i = 0; i < subdev_count; i++) { - subdevdata = &config->subdev_info[i]; - vpif_obj.sd[i] = - v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, - subdevdata->name, - &subdevdata->board_info, - NULL); - - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", - subdevdata->name); - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; - } - v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver" - " initialized\n"); - - return 0; - -probe_subdev_out: - /* free sub devices memory */ - kfree(vpif_obj.sd); - - j = VPIF_CAPTURE_MAX_DEVICES; -probe_out: - v4l2_device_unregister(&vpif_obj.v4l2_dev); - for (k = 0; k < j; k++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[k]; - /* Unregister video device */ - video_unregister_device(ch->video_dev); - } - -vpif_dev_alloc_err: - k = VPIF_CAPTURE_MAX_DEVICES-1; - res = platform_get_resource(pdev, IORESOURCE_IRQ, k); - i = res->end; - -vpif_int_err: - for (q = k; q >= 0; q--) { - for (m = i; m >= (int)res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); - if (res) - i = res->end; - } - return err; -} - -/** - * vpif_remove() - driver remove handler - * @device: ptr to platform device structure - * - * The vidoe device is unregistered - */ -static int vpif_remove(struct platform_device *device) -{ - int i; - struct channel_obj *ch; - - v4l2_device_unregister(&vpif_obj.v4l2_dev); - - /* un-register device */ - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Unregister video device */ - video_unregister_device(ch->video_dev); - } - return 0; -} - -/** - * vpif_suspend: vpif device suspend - * - * TODO: Add suspend code here - */ -static int -vpif_suspend(struct device *dev) -{ - return -1; -} - -/** - * vpif_resume: vpif device suspend - * - * TODO: Add resume code here - */ -static int -vpif_resume(struct device *dev) -{ - return -1; -} - -static const struct dev_pm_ops vpif_dev_pm_ops = { - .suspend = vpif_suspend, - .resume = vpif_resume, -}; - -static struct platform_driver vpif_driver = { - .driver = { - .name = "vpif_capture", - .owner = THIS_MODULE, - .pm = &vpif_dev_pm_ops, - }, - .probe = vpif_probe, - .remove = vpif_remove, -}; - -/** - * vpif_init: initialize the vpif driver - * - * This function registers device and driver to the kernel, requests irq - * handler and allocates memory - * for channel objects - */ -static __init int vpif_init(void) -{ - return platform_driver_register(&vpif_driver); -} - -/** - * vpif_cleanup : This function clean up the vpif capture resources - * - * This will un-registers device and driver to the kernel, frees - * requested irq handler and de-allocates memory allocated for channel - * objects. - */ -static void vpif_cleanup(void) -{ - struct platform_device *pdev; - struct resource *res; - int irq_num; - int i = 0; - - pdev = container_of(vpif_dev, struct platform_device, dev); - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { - for (irq_num = res->start; irq_num <= res->end; irq_num++) - free_irq(irq_num, - (void *)(&vpif_obj.dev[i]->channel_id)); - i++; - } - - platform_driver_unregister(&vpif_driver); - - kfree(vpif_obj.sd); - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) - kfree(vpif_obj.dev[i]); -} - -/* Function for module initialization and cleanup */ -module_init(vpif_init); -module_exit(vpif_cleanup); diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h deleted file mode 100644 index 4e12ec8..0000000 --- a/drivers/media/video/davinci/vpif_capture.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 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 VPIF_CAPTURE_H -#define VPIF_CAPTURE_H - -#ifdef __KERNEL__ - -/* Header files */ -#include -#include -#include -#include -#include -#include -#include - -#include "vpif.h" - -/* Macros */ -#define VPIF_MAJOR_RELEASE 0 -#define VPIF_MINOR_RELEASE 0 -#define VPIF_BUILD 1 -#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ - (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) - -#define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ - (V4L2_FIELD_NONE == field)) || \ - (((V4L2_FIELD_INTERLACED == field) || \ - (V4L2_FIELD_SEQ_TB == field)) || \ - (V4L2_FIELD_SEQ_BT == field))) - -#define VPIF_CAPTURE_MAX_DEVICES 2 -#define VPIF_VIDEO_INDEX 0 -#define VPIF_NUMBER_OF_OBJECTS 1 - -/* Enumerated data type to give id to each device per channel */ -enum vpif_channel_id { - VPIF_CHANNEL0_VIDEO = 0, - VPIF_CHANNEL1_VIDEO, -}; - -struct video_obj { - enum v4l2_field buf_field; - /* Currently selected or default standard */ - v4l2_std_id stdid; - /* This is to track the last input that is passed to application */ - u32 input_idx; -}; - -struct common_obj { - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *next_frm; - /* - * 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; - /* lock used to access this structure */ - struct mutex lock; - /* number of users performing IO */ - u32 io_usrs; - /* Indicates whether streaming started */ - u8 started; - /* Function pointer to set the addresses */ - void (*set_addr) (unsigned long, unsigned long, unsigned long, - unsigned long); - /* offset where Y top starts from the starting of the buffer */ - u32 ytop_off; - /* offset where Y bottom starts from the starting of the buffer */ - u32 ybtm_off; - /* offset where C top starts from the starting of the buffer */ - u32 ctop_off; - /* offset where C bottom starts from the starting of the buffer */ - u32 cbtm_off; - /* Indicates width of the image data */ - u32 width; - /* Indicates height of the image data */ - u32 height; -}; - -struct channel_obj { - /* 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 */ - int 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 vpif_channel_id channel_id; - /* index into sd table */ - int curr_sd_index; - /* ptr to current sub device information */ - struct vpif_subdev_info *curr_subdev_info; - /* vpif configuration params */ - struct vpif_params vpifparams; - /* common object array */ - struct common_obj common[VPIF_NUMBER_OF_OBJECTS]; - /* video object */ - struct video_obj video; -}; - -/* File handle structure */ -struct vpif_fh { - /* pointer to channel object for opened device */ - struct channel_obj *channel; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed[VPIF_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; -}; - -struct vpif_device { - struct v4l2_device v4l2_dev; - struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS]; - struct v4l2_subdev **sd; -}; - -struct vpif_config_params { - u8 min_numbuffers; - u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS]; - s8 device_type; - u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; - u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; - u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; - u8 max_device_type; -}; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; -}; -#endif /* End of __KERNEL__ */ -#endif /* VPIF_CAPTURE_H */ diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c deleted file mode 100644 index b2dce78..0000000 --- a/drivers/media/video/davinci/vpif_display.c +++ /dev/null @@ -1,1654 +0,0 @@ -/* - * vpif-display - VPIF display driver - * Display driver for TI DaVinci VPIF - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * 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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include - -#include "vpif_display.h" -#include "vpif.h" - -MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); -MODULE_LICENSE("GPL"); - -#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) - -#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) -#define vpif_dbg(level, debug, fmt, arg...) \ - v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) - -static int debug = 1; -static u32 ch2_numbuffers = 3; -static u32 ch3_numbuffers = 3; -static u32 ch2_bufsize = 1920 * 1080 * 2; -static u32 ch3_bufsize = 720 * 576 * 2; - -module_param(debug, int, 0644); -module_param(ch2_numbuffers, uint, S_IRUGO); -module_param(ch3_numbuffers, uint, S_IRUGO); -module_param(ch2_bufsize, uint, S_IRUGO); -module_param(ch3_bufsize, uint, S_IRUGO); - -MODULE_PARM_DESC(debug, "Debug level 0-1"); -MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)"); -MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)"); -MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)"); -MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)"); - -static struct vpif_config_params config_params = { - .min_numbuffers = 3, - .numbuffers[0] = 3, - .numbuffers[1] = 3, - .min_bufsize[0] = 720 * 480 * 2, - .min_bufsize[1] = 720 * 480 * 2, - .channel_bufsize[0] = 1920 * 1080 * 2, - .channel_bufsize[1] = 720 * 576 * 2, -}; - -static struct vpif_device vpif_obj = { {NULL} }; -static struct device *vpif_dev; - -static const struct vpif_channel_config_params ch_params[] = { - { - "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, - 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, - }, - { - "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, - 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, - }, -}; - -/* - * vpif_uservirt_to_phys: This function is used to convert user - * space virtual address to physical address. - */ -static u32 vpif_uservirt_to_phys(u32 virtp) -{ - struct mm_struct *mm = current->mm; - unsigned long physp = 0; - struct vm_area_struct *vma; - - vma = find_vma(mm, virtp); - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - physp = virt_to_phys((void *)virtp); - } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { - /* this will catch, kernel-allocated, mmaped-to-usermode addr */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - } else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, - virtp, nr_pages, 1, 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) { - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - } else { - vpif_err("get_user_pages failed\n"); - return 0; - } - } - - return physp; -} - -/* - * buffer_prepare: This is the callback function called from videobuf_qbuf() - * function the buffer is prepared and user space virtual address is converted - * into physical address - */ -static int vpif_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct vpif_fh *fh = q->priv_data; - struct common_obj *common; - unsigned long addr; - - common = &fh->channel->common[VPIF_VIDEO_INDEX]; - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = common->width; - vb->height = common->height; - vb->size = vb->width * vb->height; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - - /* if user pointer memory mechanism is used, get the physical - * address of the buffer */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (!vb->baddr) { - vpif_err("buffer_address is 0\n"); - return -EINVAL; - } - - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!ISALIGNED(vb->boff)) - goto buf_align_exit; - } - - addr = vb->boff; - if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { - if (!ISALIGNED(addr + common->ytop_off) || - !ISALIGNED(addr + common->ybtm_off) || - !ISALIGNED(addr + common->ctop_off) || - !ISALIGNED(addr + common->cbtm_off)) - goto buf_align_exit; - } - return 0; - -buf_align_exit: - vpif_err("buffer offset not aligned to 8 bytes\n"); - return -EINVAL; -} - -/* - * vpif_buffer_setup: This function allocates memory for the buffers - */ -static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (V4L2_MEMORY_MMAP != common->memory) - return 0; - - *size = config_params.channel_bufsize[ch->channel_id]; - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - - return 0; -} - -/* - * vpif_buffer_queue: This function adds the buffer to DMA queue - */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct vpif_fh *fh = q->priv_data; - struct common_obj *common; - - common = &fh->channel->common[VPIF_VIDEO_INDEX]; - - /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - vb->state = VIDEOBUF_QUEUED; -} - -/* - * vpif_buffer_release: This function is called from the videobuf layer to - * free memory allocated to the buffers - */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct vpif_fh *fh = q->priv_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - unsigned int buf_size = 0; - - common = &ch->common[VPIF_VIDEO_INDEX]; - - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; - - if (V4L2_MEMORY_MMAP != common->memory) - return; - - buf_size = config_params.channel_bufsize[ch->channel_id]; -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpif_buffer_setup, - .buf_prepare = vpif_buffer_prepare, - .buf_queue = vpif_buffer_queue, - .buf_release = vpif_buffer_release, -}; -static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; - -static void process_progressive_mode(struct common_obj *common) -{ - unsigned long addr = 0; - - /* Get the next buffer from buffer queue */ - common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); - /* Mark status of the buffer as active */ - common->next_frm->state = VIDEOBUF_ACTIVE; - - /* Set top and bottom field addrs in VPIF registers */ - addr = videobuf_to_dma_contig(common->next_frm); - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); -} - -static void process_interlaced_mode(int fid, struct common_obj *common) -{ - /* device field id and local field id are in sync */ - /* If this is even field */ - if (0 == fid) { - if (common->cur_frm == common->next_frm) - return; - - /* one frame is displayed If next frame is - * available, release cur_frm and move on */ - /* Copy frame display time */ - do_gettimeofday(&common->cur_frm->ts); - /* Change status of the cur_frm */ - common->cur_frm->state = VIDEOBUF_DONE; - /* unlock semaphore on cur_frm */ - wake_up_interruptible(&common->cur_frm->done); - /* Make cur_frm pointing to next_frm */ - common->cur_frm = common->next_frm; - - } else if (1 == fid) { /* odd field */ - if (list_empty(&common->dma_queue) - || (common->cur_frm != common->next_frm)) { - return; - } - /* one field is displayed configure the next - * frame if it is available else hold on current - * frame */ - /* Get next from the buffer queue */ - process_progressive_mode(common); - - } -} - -/* - * vpif_channel_isr: It changes status of the displayed buffer, takes next - * buffer from the queue and sets its address in VPIF registers - */ -static irqreturn_t vpif_channel_isr(int irq, void *dev_id) -{ - struct vpif_device *dev = &vpif_obj; - struct channel_obj *ch; - struct common_obj *common; - enum v4l2_field field; - int fid = -1, i; - int channel_id = 0; - - channel_id = *(int *)(dev_id); - ch = dev->dev[channel_id]; - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; - for (i = 0; i < VPIF_NUMOBJECTS; i++) { - common = &ch->common[i]; - /* If streaming is started in this channel */ - if (0 == common->started) - continue; - - if (1 == ch->vpifparams.std_info.frm_fmt) { - if (list_empty(&common->dma_queue)) - continue; - - /* Progressive mode */ - if (!channel_first_int[i][channel_id]) { - /* Mark status of the cur_frm to - * done and unlock semaphore on it */ - do_gettimeofday(&common->cur_frm->ts); - common->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&common->cur_frm->done); - /* Make cur_frm pointing to next_frm */ - common->cur_frm = common->next_frm; - } - - channel_first_int[i][channel_id] = 0; - process_progressive_mode(common); - } else { - /* Interlaced mode */ - /* If it is first interrupt, ignore it */ - - if (channel_first_int[i][channel_id]) { - channel_first_int[i][channel_id] = 0; - continue; - } - - if (0 == i) { - ch->field_id ^= 1; - /* Get field id from VPIF registers */ - fid = vpif_channel_getfid(ch->channel_id + 2); - /* If fid does not match with stored field id */ - if (fid != ch->field_id) { - /* Make them in sync */ - if (0 == fid) - ch->field_id = fid; - - return IRQ_HANDLED; - } - } - process_interlaced_mode(fid, common); - } - } - - return IRQ_HANDLED; -} - -static int vpif_get_std_info(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - struct vpif_params *vpifparams = &ch->vpifparams; - struct vpif_channel_config_params *std_info = &vpifparams->std_info; - const struct vpif_channel_config_params *config; - - int index; - - std_info->stdid = vid_ch->stdid; - if (!std_info->stdid) - return -1; - - for (index = 0; index < ARRAY_SIZE(ch_params); index++) { - config = &ch_params[index]; - if (config->stdid & std_info->stdid) { - memcpy(std_info, config, sizeof(*config)); - break; - } - } - - if (index == ARRAY_SIZE(ch_params)) - return -1; - - common->fmt.fmt.pix.width = std_info->width; - common->fmt.fmt.pix.height = std_info->height; - vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", - common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); - - /* Set height and width paramateres */ - ch->common[VPIF_VIDEO_INDEX].height = std_info->height; - ch->common[VPIF_VIDEO_INDEX].width = std_info->width; - - return 0; -} - -/* - * vpif_calculate_offsets: This function calculates buffers offset for Y and C - * in the top and bottom field - */ -static void vpif_calculate_offsets(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct vpif_params *vpifparams = &ch->vpifparams; - enum v4l2_field field = common->fmt.fmt.pix.field; - struct video_obj *vid_ch = &ch->video; - unsigned int hpitch, vpitch, sizeimage; - - if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { - if (ch->vpifparams.std_info.frm_fmt) - vid_ch->buf_field = V4L2_FIELD_NONE; - else - vid_ch->buf_field = V4L2_FIELD_INTERLACED; - } else { - vid_ch->buf_field = common->fmt.fmt.pix.field; - } - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = common->fmt.fmt.pix.sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { - common->ytop_off = 0; - common->ybtm_off = hpitch; - common->ctop_off = sizeimage / 2; - common->cbtm_off = sizeimage / 2 + hpitch; - } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { - common->ytop_off = 0; - common->ybtm_off = sizeimage / 4; - common->ctop_off = sizeimage / 2; - common->cbtm_off = common->ctop_off + sizeimage / 4; - } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { - common->ybtm_off = 0; - common->ytop_off = sizeimage / 4; - common->cbtm_off = sizeimage / 2; - common->ctop_off = common->cbtm_off + sizeimage / 4; - } - - if ((V4L2_FIELD_NONE == vid_ch->buf_field) || - (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { - vpifparams->video_params.storage_mode = 1; - } else { - vpifparams->video_params.storage_mode = 0; - } - - if (ch->vpifparams.std_info.frm_fmt == 1) { - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - } else { - if ((field == V4L2_FIELD_ANY) || - (field == V4L2_FIELD_INTERLACED)) - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline * 2; - else - vpifparams->video_params.hpitch = - common->fmt.fmt.pix.bytesperline; - } - - ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid; -} - -static void vpif_config_format(struct channel_obj *ch) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - common->fmt.fmt.pix.field = V4L2_FIELD_ANY; - if (config_params.numbuffers[ch->channel_id] == 0) - common->memory = V4L2_MEMORY_USERPTR; - else - common->memory = V4L2_MEMORY_MMAP; - - common->fmt.fmt.pix.sizeimage = - config_params.channel_bufsize[ch->channel_id]; - common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; - common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; -} - -static int vpif_check_format(struct channel_obj *ch, - struct v4l2_pix_format *pixfmt) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - enum v4l2_field field = pixfmt->field; - u32 sizeimage, hpitch, vpitch; - - if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) - goto invalid_fmt_exit; - - if (!(VPIF_VALID_FIELD(field))) - goto invalid_fmt_exit; - - if (pixfmt->bytesperline <= 0) - goto invalid_pitch_exit; - - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; - - if (vpif_get_std_info(ch)) { - vpif_err("Error getting the standard info\n"); - return -EINVAL; - } - - hpitch = pixfmt->bytesperline; - vpitch = sizeimage / (hpitch * 2); - - /* Check for valid value of pitch */ - if ((hpitch < ch->vpifparams.std_info.width) || - (vpitch < ch->vpifparams.std_info.height)) - goto invalid_pitch_exit; - - /* Check for 8 byte alignment */ - if (!ISALIGNED(hpitch)) { - vpif_err("invalid pitch alignment\n"); - return -EINVAL; - } - pixfmt->width = common->fmt.fmt.pix.width; - pixfmt->height = common->fmt.fmt.pix.height; - - return 0; - -invalid_fmt_exit: - vpif_err("invalid field format\n"); - return -EINVAL; - -invalid_pitch_exit: - vpif_err("invalid pitch\n"); - return -EINVAL; -} - -static void vpif_config_addr(struct channel_obj *ch, int muxmode) -{ - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { - common->set_addr = ch3_set_videobuf_addr; - } else { - if (2 == muxmode) - common->set_addr = ch2_set_videobuf_addr_yc_nmux; - else - common->set_addr = ch2_set_videobuf_addr; - } -} - -/* - * vpif_mmap: It is used to map kernel space buffers into user spaces - */ -static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) -{ - struct vpif_fh *fh = filep->private_data; - struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX]; - - return videobuf_mmap_mapper(&common->buffer_queue, vma); -} - -/* - * vpif_poll: It is used for select/poll system call - */ -static unsigned int vpif_poll(struct file *filep, poll_table *wait) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (common->started) - return videobuf_poll_stream(filep, &common->buffer_queue, wait); - - return 0; -} - -/* - * vpif_open: It creates object of file handle structure and stores it in - * private_data member of filepointer - */ -static int vpif_open(struct file *filep) -{ - struct video_device *vdev = video_devdata(filep); - struct channel_obj *ch = NULL; - struct vpif_fh *fh = NULL; - - ch = video_get_drvdata(vdev); - /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL); - if (fh == NULL) { - vpif_err("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 = ch; - fh->initialized = 0; - if (!ch->initialized) { - fh->initialized = 1; - ch->initialized = 1; - memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); - } - - /* Increment channel usrs counter */ - atomic_inc(&ch->usrs); - /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */ - fh->io_allowed[VPIF_VIDEO_INDEX] = 0; - /* Initialize priority of this instance to default priority */ - fh->prio = V4L2_PRIORITY_UNSET; - v4l2_prio_open(&ch->prio, &fh->prio); - - return 0; -} - -/* - * vpif_release: This function deletes buffer queue, frees the buffers and - * the vpif file handle - */ -static int vpif_release(struct file *filep) -{ - struct vpif_fh *fh = filep->private_data; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - /* if this instance is doing IO */ - if (fh->io_allowed[VPIF_VIDEO_INDEX]) { - /* Reset io_usrs member of channel object */ - common->io_usrs = 0; - /* Disable channel */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - enable_channel2(0); - channel2_intr_enable(0); - } - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel3(0); - channel3_intr_enable(0); - } - common->started = 0; - /* Free buffers allocated */ - videobuf_queue_cancel(&common->buffer_queue); - videobuf_mmap_free(&common->buffer_queue); - common->numbuffers = - config_params.numbuffers[ch->channel_id]; - } - - mutex_unlock(&common->lock); - - /* Decrement channel usrs counter */ - atomic_dec(&ch->usrs); - /* If this file handle has initialize encoder device, reset it */ - if (fh->initialized) - ch->initialized = 0; - - /* Close the priority */ - v4l2_prio_close(&ch->prio, &fh->prio); - filep->private_data = NULL; - fh->initialized = 0; - kfree(fh); - - return 0; -} - -/* functions implementing ioctls */ - -static int vpif_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpif_display_config *config = vpif_dev->platform_data; - - cap->version = VPIF_DISPLAY_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); - strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); - strlcpy(cap->card, config->card_name, sizeof(cap->card)); - - return 0; -} - -static int vpif_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - if (fmt->index != 0) { - vpif_err("Invalid format index\n"); - return -EINVAL; - } - - /* Fill in the information about format */ - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); - fmt->pixelformat = V4L2_PIX_FMT_YUV422P; - - return 0; -} - -static int vpif_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - /* Check the validity of the buffer type */ - if (common->fmt.type != fmt->type) - return -EINVAL; - - /* Fill in the information about format */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (vpif_get_std_info(ch)) { - vpif_err("Error getting the standard info\n"); - return -EINVAL; - } - - *fmt = common->fmt; - mutex_unlock(&common->lock); - return 0; -} - -static int vpif_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct v4l2_pix_format *pixfmt; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) - || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_dbg(1, debug, "Channel Busy\n"); - return -EBUSY; - } - - /* Check for the priority */ - ret = v4l2_prio_check(&ch->prio, &fh->prio); - if (0 != ret) - return ret; - fh->initialized = 1; - } - - if (common->started) { - vpif_dbg(1, debug, "Streaming in progress\n"); - return -EBUSY; - } - - pixfmt = &fmt->fmt.pix; - /* Check for valid field format */ - ret = vpif_check_format(ch, pixfmt); - if (ret) - return ret; - - /* store the pix format in the channel object */ - common->fmt.fmt.pix = *pixfmt; - /* store the format in the channel object */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - common->fmt = *fmt; - mutex_unlock(&common->lock); - - return 0; -} - -static int vpif_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - int ret = 0; - - ret = vpif_check_format(ch, pixfmt); - if (ret) { - *pixfmt = common->fmt.fmt.pix; - pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2; - } - - return ret; -} - -static int vpif_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbuf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common; - enum v4l2_field field; - u8 index = 0; - int ret = 0; - - /* This file handle has not initialized the channel, - It is not allowed to do settings */ - if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) - || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { - if (!fh->initialized) { - vpif_err("Channel Busy\n"); - return -EBUSY; - } - } - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type) - return -EINVAL; - - index = VPIF_VIDEO_INDEX; - - common = &ch->common[index]; - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (common->fmt.type != reqbuf->type) { - ret = -EINVAL; - goto reqbuf_exit; - } - - if (0 != common->io_usrs) { - ret = -EBUSY; - goto reqbuf_exit; - } - - if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) - field = V4L2_FIELD_INTERLACED; - else - field = common->fmt.fmt.pix.field; - } else { - field = V4L2_VBI_INTERLACED; - } - - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, field, - sizeof(struct videobuf_buffer), fh); - - /* Set io allowed member of file handle to TRUE */ - fh->io_allowed[index] = 1; - /* Increment io usrs member of channel object to 1 */ - common->io_usrs = 1; - /* Store type of memory requested in channel object */ - common->memory = reqbuf->memory; - INIT_LIST_HEAD(&common->dma_queue); - - /* Allocate buffers */ - ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); - -reqbuf_exit: - mutex_unlock(&common->lock); - return ret; -} - -static int vpif_querybuf(struct file *file, void *priv, - struct v4l2_buffer *tbuf) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (common->fmt.type != tbuf->type) - return -EINVAL; - - return videobuf_querybuf(&common->buffer_queue, tbuf); -} - -static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_buffer tbuf = *buf; - struct videobuf_buffer *buf1; - unsigned long addr = 0; - unsigned long flags; - int ret = 0; - - if (common->fmt.type != tbuf.type) - return -EINVAL; - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh->io_allowed\n"); - return -EACCES; - } - - if (!(list_empty(&common->dma_queue)) || - (common->cur_frm != common->next_frm) || - !(common->started) || - (common->started && (0 == ch->field_id))) - return videobuf_qbuf(&common->buffer_queue, buf); - - /* bufferqueue is empty store buffer address in VPIF registers */ - mutex_lock(&common->buffer_queue.vb_lock); - buf1 = common->buffer_queue.bufs[tbuf.index]; - if (buf1->memory != tbuf.memory) { - vpif_err("invalid buffer type\n"); - goto qbuf_exit; - } - - if ((buf1->state == VIDEOBUF_QUEUED) || - (buf1->state == VIDEOBUF_ACTIVE)) { - vpif_err("invalid state\n"); - goto qbuf_exit; - } - - switch (buf1->memory) { - case V4L2_MEMORY_MMAP: - if (buf1->baddr == 0) - goto qbuf_exit; - break; - - case V4L2_MEMORY_USERPTR: - if (tbuf.length < buf1->bsize) - goto qbuf_exit; - - if ((VIDEOBUF_NEEDS_INIT != buf1->state) - && (buf1->baddr != tbuf.m.userptr)) - vpif_buffer_release(&common->buffer_queue, buf1); - buf1->baddr = tbuf.m.userptr; - break; - - default: - goto qbuf_exit; - } - - local_irq_save(flags); - ret = vpif_buffer_prepare(&common->buffer_queue, buf1, - common->buffer_queue.field); - if (ret < 0) { - local_irq_restore(flags); - goto qbuf_exit; - } - - buf1->state = VIDEOBUF_ACTIVE; - addr = buf1->boff; - common->next_frm = buf1; - if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - common->set_addr((addr + common->ytop_off), - (addr + common->ybtm_off), - (addr + common->ctop_off), - (addr + common->cbtm_off)); - } - - local_irq_restore(flags); - list_add_tail(&buf1->stream, &common->buffer_queue.stream); - mutex_unlock(&common->buffer_queue.vb_lock); - return 0; - -qbuf_exit: - mutex_unlock(&common->buffer_queue.vb_lock); - return -EINVAL; -} - -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if (!(*std_id & DM646X_V4L2_STD)) - return -EINVAL; - - if (common->started) { - vpif_err("streaming in progress\n"); - return -EBUSY; - } - - /* Call encoder subdevice function to set the standard */ - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - ch->video.stdid = *std_id; - /* Get the information about the standard */ - if (vpif_get_std_info(ch)) { - vpif_err("Error getting the standard info\n"); - return -EINVAL; - } - - if ((ch->vpifparams.std_info.width * - ch->vpifparams.std_info.height * 2) > - config_params.channel_bufsize[ch->channel_id]) { - vpif_err("invalid std for this size\n"); - ret = -EINVAL; - goto s_std_exit; - } - - common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; - /* Configure the default format information */ - vpif_config_format(ch); - - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_std_output, *std_id); - if (ret < 0) { - vpif_err("Failed to set output standard\n"); - goto s_std_exit; - } - - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, - s_std, *std_id); - if (ret < 0) - vpif_err("Failed to set standard for sub devices\n"); - -s_std_exit: - mutex_unlock(&common->lock); - return ret; -} - -static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - *std = ch->video.stdid; - return 0; -} - -static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - return videobuf_dqbuf(&common->buffer_queue, p, - (file->f_flags & O_NONBLOCK)); -} - -static int vpif_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; - struct vpif_params *vpif = &ch->vpifparams; - struct vpif_display_config *vpif_config_data = - vpif_dev->platform_data; - unsigned long addr = 0; - int ret = 0; - - if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - vpif_err("buffer type not supported\n"); - return -EINVAL; - } - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh->io_allowed\n"); - return -EACCES; - } - - /* If Streaming is already started, return error */ - if (common->started) { - vpif_err("channel->started\n"); - return -EBUSY; - } - - if ((ch->channel_id == VPIF_CHANNEL2_VIDEO - && oth_ch->common[VPIF_VIDEO_INDEX].started && - ch->vpifparams.std_info.ycmux_mode == 0) - || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) - && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { - vpif_err("other channel is using\n"); - return -EBUSY; - } - - ret = vpif_check_format(ch, &common->fmt.fmt.pix); - if (ret < 0) - return ret; - - /* Call videobuf_streamon to start streaming in videobuf */ - ret = videobuf_streamon(&common->buffer_queue); - if (ret < 0) { - vpif_err("videobuf_streamon\n"); - return ret; - } - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_err("buffer queue is empty\n"); - ret = -EIO; - goto streamon_exit; - } - - /* Get the next frame from the buffer queue */ - common->next_frm = common->cur_frm = - list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - - list_del(&common->cur_frm->queue); - /* Mark state of the current frame to active */ - common->cur_frm->state = VIDEOBUF_ACTIVE; - - /* Initialize field_id and started member */ - ch->field_id = 0; - common->started = 1; - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - addr = common->cur_frm->boff; - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((ch->vpifparams.std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) - && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) - || (!ch->vpifparams.std_info.frm_fmt - && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_err("conflict in field format and std format\n"); - ret = -EINVAL; - goto streamon_exit; - } - - /* clock settings */ - ret = - vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, - ch->vpifparams.std_info.hd_sd); - if (ret < 0) { - vpif_err("can't set clock\n"); - goto streamon_exit; - } - - /* set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id + 2); - if (ret < 0) - goto streamon_exit; - - common->started = ret; - vpif_config_addr(ch, ret); - common->set_addr((addr + common->ytop_off), - (addr + common->ybtm_off), - (addr + common->ctop_off), - (addr + common->cbtm_off)); - - /* Set interrupt for both the fields in VPIF - Register enable channel in VPIF register */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - channel2_intr_assert(); - channel2_intr_enable(1); - enable_channel2(1); - } - - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) - || (common->started == 2)) { - channel3_intr_assert(); - channel3_intr_enable(1); - enable_channel3(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - } - -streamon_exit: - mutex_unlock(&common->lock); - return ret; -} - -static int vpif_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - - if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - vpif_err("buffer type not supported\n"); - return -EINVAL; - } - - if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh->io_allowed\n"); - return -EACCES; - } - - if (!common->started) { - vpif_err("channel->started\n"); - return -EINVAL; - } - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* disable channel */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - enable_channel2(0); - channel2_intr_enable(0); - } - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || - (2 == common->started)) { - enable_channel3(0); - channel3_intr_enable(0); - } - } - - common->started = 0; - mutex_unlock(&common->lock); - - return videobuf_streamoff(&common->buffer_queue); -} - -static int vpif_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *crop) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type) - return -EINVAL; - - crop->bounds.left = crop->bounds.top = 0; - crop->defrect.left = crop->defrect.top = 0; - crop->defrect.height = crop->bounds.height = common->height; - crop->defrect.width = crop->bounds.width = common->width; - - return 0; -} - -static int vpif_enum_output(struct file *file, void *fh, - struct v4l2_output *output) -{ - - struct vpif_display_config *config = vpif_dev->platform_data; - - if (output->index >= config->output_count) { - vpif_dbg(1, debug, "Invalid output index\n"); - return -EINVAL; - } - - strcpy(output->name, config->output[output->index]); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = DM646X_V4L2_STD; - - return 0; -} - -static int vpif_s_output(struct file *file, void *priv, unsigned int i) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; - - if (mutex_lock_interruptible(&common->lock)) - return -ERESTARTSYS; - - if (common->started) { - vpif_err("Streaming in progress\n"); - ret = -EBUSY; - goto s_output_exit; - } - - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_routing, 0, i, 0); - - if (ret < 0) - vpif_err("Failed to set output standard\n"); - - vid_ch->output_id = i; - -s_output_exit: - mutex_unlock(&common->lock); - return ret; -} - -static int vpif_g_output(struct file *file, void *priv, unsigned int *i) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *i = vid_ch->output_id; - - return 0; -} - -static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - *p = v4l2_prio_max(&ch->prio); - - return 0; -} - -static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) -{ - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - - return v4l2_prio_change(&ch->prio, &fh->prio, p); -} - -/* vpif display ioctl operations */ -static const struct v4l2_ioctl_ops vpif_ioctl_ops = { - .vidioc_querycap = vpif_querycap, - .vidioc_g_priority = vpif_g_priority, - .vidioc_s_priority = vpif_s_priority, - .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out, - .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out, - .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out, - .vidioc_reqbufs = vpif_reqbufs, - .vidioc_querybuf = vpif_querybuf, - .vidioc_qbuf = vpif_qbuf, - .vidioc_dqbuf = vpif_dqbuf, - .vidioc_streamon = vpif_streamon, - .vidioc_streamoff = vpif_streamoff, - .vidioc_s_std = vpif_s_std, - .vidioc_g_std = vpif_g_std, - .vidioc_enum_output = vpif_enum_output, - .vidioc_s_output = vpif_s_output, - .vidioc_g_output = vpif_g_output, - .vidioc_cropcap = vpif_cropcap, -}; - -static const struct v4l2_file_operations vpif_fops = { - .owner = THIS_MODULE, - .open = vpif_open, - .release = vpif_release, - .ioctl = video_ioctl2, - .mmap = vpif_mmap, - .poll = vpif_poll -}; - -static struct video_device vpif_video_template = { - .name = "vpif", - .fops = &vpif_fops, - .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = DM646X_V4L2_STD, - .current_norm = V4L2_STD_625_50, - -}; - -/*Configure the channels, buffer sizei, request irq */ -static int initialize_vpif(void) -{ - int free_channel_objects_index; - int free_buffer_channel_index; - int free_buffer_index; - int err = 0, i, j; - - /* Default number of buffers should be 3 */ - if ((ch2_numbuffers > 0) && - (ch2_numbuffers < config_params.min_numbuffers)) - ch2_numbuffers = config_params.min_numbuffers; - if ((ch3_numbuffers > 0) && - (ch3_numbuffers < config_params.min_numbuffers)) - ch3_numbuffers = config_params.min_numbuffers; - - /* Set buffer size to min buffers size if invalid buffer size is - * given */ - if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]) - ch2_bufsize = - config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]; - if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]) - ch3_bufsize = - config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]; - - config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers; - - if (ch2_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] = - ch2_bufsize; - } - config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers; - - if (ch3_numbuffers) { - config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] = - ch3_bufsize; - } - - /* Allocate memory for six channel objects */ - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - vpif_obj.dev[i] = - kmalloc(sizeof(struct channel_obj), GFP_KERNEL); - /* If memory allocation fails, return error */ - if (!vpif_obj.dev[i]) { - free_channel_objects_index = i; - err = -ENOMEM; - goto vpif_init_free_channel_objects; - } - } - - free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES; - free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS; - free_buffer_index = config_params.numbuffers[i - 1]; - - return 0; - -vpif_init_free_channel_objects: - for (j = 0; j < free_channel_objects_index; j++) - kfree(vpif_obj.dev[j]); - return err; -} - -/* - * vpif_probe: This function creates device entries by register itself to the - * V4L2 driver and initializes fields of each channel objects - */ -static __init int vpif_probe(struct platform_device *pdev) -{ - struct vpif_subdev_info *subdevdata; - struct vpif_display_config *config; - int i, j = 0, k, q, m, err = 0; - struct i2c_adapter *i2c_adap; - struct common_obj *common; - struct channel_obj *ch; - struct video_device *vfd; - struct resource *res; - int subdev_count; - - vpif_dev = &pdev->dev; - - err = initialize_vpif(); - - if (err) { - v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); - return err; - } - - err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); - if (err) { - v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - return err; - } - - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { - for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Display", - (void *)(&vpif_obj.dev[k]->channel_id))) { - err = -EBUSY; - goto vpif_int_err; - } - } - k++; - } - - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (vfd == NULL) { - for (j = 0; j < i; j++) { - ch = vpif_obj.dev[j]; - video_device_release(ch->video_dev); - } - err = -ENOMEM; - goto vpif_int_err; - } - - /* Initialize field of video device */ - *vfd = vpif_video_template; - vfd->v4l2_dev = &vpif_obj.v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", - (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, - (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, - (VPIF_DISPLAY_VERSION_CODE) & 0xff); - - /* Set video_dev to the video device */ - ch->video_dev = vfd; - } - - for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - /* Initialize field of the channel objects */ - atomic_set(&ch->usrs, 0); - for (k = 0; k < VPIF_NUMOBJECTS; k++) { - ch->common[k].numbuffers = 0; - common = &ch->common[k]; - common->io_usrs = 0; - common->started = 0; - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - common->numbuffers = 0; - common->set_addr = NULL; - common->ytop_off = common->ybtm_off = 0; - common->ctop_off = common->cbtm_off = 0; - common->cur_frm = common->next_frm = NULL; - memset(&common->fmt, 0, sizeof(common->fmt)); - common->numbuffers = config_params.numbuffers[k]; - - } - ch->initialized = 0; - ch->channel_id = j; - if (j < 2) - ch->common[VPIF_VIDEO_INDEX].numbuffers = - config_params.numbuffers[ch->channel_id]; - else - ch->common[VPIF_VIDEO_INDEX].numbuffers = 0; - - memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); - - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - ch->common[VPIF_VIDEO_INDEX].fmt.type = - V4L2_BUF_TYPE_VIDEO_OUTPUT; - - /* register video device */ - vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", - (int)ch, (int)&ch->video_dev); - - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 3 : 2)); - if (err < 0) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - subdev_count = config->subdev_count; - subdevdata = config->subdevinfo; - vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - for (i = 0; i < subdev_count; i++) { - vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, subdevdata[i].name, - &subdevdata[i].board_info, - NULL); - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; - } - - return 0; - -probe_subdev_out: - kfree(vpif_obj.sd); -probe_out: - for (k = 0; k < j; k++) { - ch = vpif_obj.dev[k]; - video_unregister_device(ch->video_dev); - video_device_release(ch->video_dev); - ch->video_dev = NULL; - } -vpif_int_err: - v4l2_device_unregister(&vpif_obj.v4l2_dev); - vpif_err("VPIF IRQ request failed\n"); - for (q = k; k >= 0; k--) { - for (m = i; m >= res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); - res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); - m = res->end; - } - - return err; -} - -/* - * vpif_remove: It un-register channels from V4L2 driver - */ -static int vpif_remove(struct platform_device *device) -{ - struct channel_obj *ch; - int i; - - v4l2_device_unregister(&vpif_obj.v4l2_dev); - - /* un-register device */ - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Unregister video device */ - video_unregister_device(ch->video_dev); - - ch->video_dev = NULL; - } - - return 0; -} - -static struct platform_driver vpif_driver = { - .driver = { - .name = "vpif_display", - .owner = THIS_MODULE, - }, - .probe = vpif_probe, - .remove = vpif_remove, -}; - -static __init int vpif_init(void) -{ - return platform_driver_register(&vpif_driver); -} - -/* - * vpif_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 vpif_cleanup(void) -{ - struct platform_device *pdev; - struct resource *res; - int irq_num; - int i = 0; - - pdev = container_of(vpif_dev, struct platform_device, dev); - - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { - for (irq_num = res->start; irq_num <= res->end; irq_num++) - free_irq(irq_num, - (void *)(&vpif_obj.dev[i]->channel_id)); - i++; - } - - platform_driver_unregister(&vpif_driver); - kfree(vpif_obj.sd); - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) - kfree(vpif_obj.dev[i]); -} - -module_init(vpif_init); -module_exit(vpif_cleanup); diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h deleted file mode 100644 index a2a7cd1..0000000 --- a/drivers/media/video/davinci/vpif_display.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * DM646x display header file - * - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * 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 version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef DAVINCIHD_DISPLAY_H -#define DAVINCIHD_DISPLAY_H - -/* Header files */ -#include -#include -#include -#include -#include -#include - -#include "vpif.h" - -/* Macros */ -#define VPIF_MAJOR_RELEASE (0) -#define VPIF_MINOR_RELEASE (0) -#define VPIF_BUILD (1) - -#define VPIF_DISPLAY_VERSION_CODE \ - ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) - -#define VPIF_VALID_FIELD(field) \ - (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ - (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \ - (V4L2_FIELD_SEQ_BT == field))) - -#define VPIF_DISPLAY_MAX_DEVICES (2) -#define VPIF_SLICED_BUF_SIZE (256) -#define VPIF_SLICED_MAX_SERVICES (3) -#define VPIF_VIDEO_INDEX (0) -#define VPIF_VBI_INDEX (1) -#define VPIF_HBI_INDEX (2) - -/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/ -#define VPIF_NUMOBJECTS (1) - -/* Macros */ -#define ISALIGNED(a) (0 == ((a) & 7)) - -/* enumerated data types */ -/* Enumerated data type to give id to each device per channel */ -enum vpif_channel_id { - VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */ - VPIF_CHANNEL3_VIDEO, /* Channel3 Video */ -}; - -/* structures */ - -struct video_obj { - enum v4l2_field buf_field; - u32 latest_only; /* indicate whether to return - * most recent displayed frame only */ - v4l2_std_id stdid; /* Currently selected or default - * standard */ - u32 output_id; /* Current output id */ -}; - -struct vbi_obj { - int num_services; - struct vpif_vbi_params vbiparams; /* vpif parameters for the raw - * vbi data */ -}; - -struct common_obj { - /* Buffer specific parameters */ - u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for - * storing frames */ - u32 numbuffers; /* number of buffers */ - struct videobuf_buffer *cur_frm; /* Pointer pointing to current - * videobuf_buffer */ - struct videobuf_buffer *next_frm; /* Pointer pointing to next - * videobuf_buffer */ - enum v4l2_memory memory; /* This field keeps track of - * type of buffer exchange - * method user has selected */ - struct v4l2_format fmt; /* Used to store the format */ - struct videobuf_queue buffer_queue; /* Buffer queue used in - * video-buf */ - struct list_head dma_queue; /* Queue of filled frames */ - spinlock_t irqlock; /* Used in video-buf */ - - /* channel specific parameters */ - struct mutex lock; /* lock used to access this - * structure */ - u32 io_usrs; /* number of users performing - * IO */ - u8 started; /* Indicates whether streaming - * started */ - u32 ytop_off; /* offset of Y top from the - * starting of the buffer */ - u32 ybtm_off; /* offset of Y bottom from the - * starting of the buffer */ - u32 ctop_off; /* offset of C top from the - * starting of the buffer */ - u32 cbtm_off; /* offset of C bottom from the - * starting of the buffer */ - /* Function pointer to set the addresses */ - void (*set_addr) (unsigned long, unsigned long, - unsigned long, unsigned long); - u32 height; - u32 width; -}; - -struct channel_obj { - /* V4l2 specific parameters */ - struct video_device *video_dev; /* Identifies video device for - * this channel */ - struct v4l2_prio_state prio; /* Used to keep track of state of - * the priority */ - atomic_t usrs; /* number of open instances of - * the channel */ - u32 field_id; /* Indicates id of the field - * which is being displayed */ - u8 initialized; /* flag to indicate whether - * encoder is initialized */ - - enum vpif_channel_id channel_id;/* Identifies channel */ - struct vpif_params vpifparams; - struct common_obj common[VPIF_NUMOBJECTS]; - struct video_obj video; - struct vbi_obj vbi; -}; - -/* File handle structure */ -struct vpif_fh { - struct channel_obj *channel; /* pointer to channel object for - * opened device */ - u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle - * is doing IO */ - enum v4l2_priority prio; /* Used to keep track priority of - * this instance */ - u8 initialized; /* Used to keep track of whether this - * file handle has initialized - * channel or not */ -}; - -/* vpif device structure */ -struct vpif_device { - struct v4l2_device v4l2_dev; - struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS]; - struct v4l2_subdev **sd; - -}; - -struct vpif_config_params { - u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; - u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; - u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; - u8 min_numbuffers; -}; - -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; - u16 enc_service_id; - u8 bytestowrite; -}; - -#endif /* DAVINCIHD_DISPLAY_H */ diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c deleted file mode 100644 index 7918680..0000000 --- a/drivers/media/video/davinci/vpss.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2009 Texas Instruments. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * common vpss system module platform driver for all video drivers. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VPSS Driver"); -MODULE_AUTHOR("Texas Instruments"); - -/* DM644x defines */ -#define DM644X_SBL_PCR_VPSS (4) - -#define DM355_VPSSBL_INTSEL 0x10 -#define DM355_VPSSBL_EVTSEL 0x14 -/* vpss BL register offsets */ -#define DM355_VPSSBL_CCDCMUX 0x1c -/* vpss CLK register offsets */ -#define DM355_VPSSCLK_CLKCTRL 0x04 -/* masks and shifts */ -#define VPSS_HSSISEL_SHIFT 4 -/* - * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, - * IPIPE_INT1_SDR - vpss_int5 - */ -#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 -/* VENCINT - vpss_int8 */ -#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 - -#define DM365_ISP5_PCCR 0x04 -#define DM365_ISP5_INTSEL1 0x10 -#define DM365_ISP5_INTSEL2 0x14 -#define DM365_ISP5_INTSEL3 0x18 -#define DM365_ISP5_CCDCMUX 0x20 -#define DM365_ISP5_PG_FRAME_SIZE 0x28 -#define DM365_VPBE_CLK_CTRL 0x00 -/* - * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, - * AF - vpss_int3 - */ -#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 -/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ -#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f -/* VENC - vpss_int8 */ -#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 - -/* masks and shifts for DM365*/ -#define DM365_CCDC_PG_VD_POL_SHIFT 0 -#define DM365_CCDC_PG_HD_POL_SHIFT 1 - -#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) -#define CCD_SRC_SEL_SHIFT 4 - -/* Different SoC platforms supported by this driver */ -enum vpss_platform_type { - DM644X, - DM355, - DM365, -}; - -/* - * vpss operations. Depends on platform. Not all functions are available - * on all platforms. The api, first check if a functio is available before - * invoking it. In the probe, the function ptrs are intialized based on - * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. - */ -struct vpss_hw_ops { - /* enable clock */ - int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); - /* select input to ccdc */ - void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); - /* clear wbl overflow bit */ - int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); -}; - -/* vpss configuration */ -struct vpss_oper_config { - __iomem void *vpss_regs_base0; - __iomem void *vpss_regs_base1; - enum vpss_platform_type platform; - spinlock_t vpss_lock; - struct vpss_hw_ops hw_ops; -}; - -static struct vpss_oper_config oper_cfg; - -/* register access routines */ -static inline u32 bl_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -static inline void bl_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static inline u32 vpss_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base1 + offset); -} - -static inline void vpss_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); -} - -/* For DM365 only */ -static inline u32 isp5_read(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -/* For DM365 only */ -static inline void isp5_write(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; - - /* if we are using pattern generator, enable it */ - if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) - temp |= 0x08; - - temp |= (src_sel << CCD_SRC_SEL_SHIFT); - isp5_write(temp, DM365_ISP5_CCDCMUX); -} - -static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); -} - -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - if (!oper_cfg.hw_ops.select_ccdc_source) - return -EINVAL; - - oper_cfg.hw_ops.select_ccdc_source(src_sel); - return 0; -} -EXPORT_SYMBOL(vpss_select_ccdc_source); - -static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - u32 mask = 1, val; - - if (wbl_sel < VPSS_PCR_AEW_WBL_0 || - wbl_sel > VPSS_PCR_CCDC_WBL_O) - return -EINVAL; - - /* writing a 0 clear the overflow */ - mask = ~(mask << wbl_sel); - val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; - bl_regw(val, DM644X_SBL_PCR_VPSS); - return 0; -} - -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - if (!oper_cfg.hw_ops.clear_wbl_overflow) - return -EINVAL; - - return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); -} -EXPORT_SYMBOL(vpss_clear_wbl_overflow); - -/* - * dm355_enable_clock - Enable VPSS Clock - * @clock_sel: CLock to be enabled/disabled - * @en: enable/disable flag - * - * This is called to enable or disable a vpss clock - */ -static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0; - - switch (clock_sel) { - case VPSS_VPBE_CLOCK: - /* nothing since lsb */ - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - break; - case VPSS_CFALD_CLOCK: - shift = 3; - break; - case VPSS_H3A_CLOCK: - shift = 4; - break; - case VPSS_IPIPE_CLOCK: - shift = 5; - break; - case VPSS_CCDC_CLOCK: - shift = 6; - break; - default: - printk(KERN_ERR "dm355_enable_clock:" - " Invalid selector: %d\n", clock_sel); - return -EINVAL; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); - if (!en) - utemp &= ~(mask << shift); - else - utemp |= (mask << shift); - - vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - return 0; -} - -static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; - u32 (*read)(u32 offset) = isp5_read; - void(*write)(u32 val, u32 offset) = isp5_write; - - switch (clock_sel) { - case VPSS_BL_CLOCK: - break; - case VPSS_CCDC_CLOCK: - shift = 1; - break; - case VPSS_H3A_CLOCK: - shift = 2; - break; - case VPSS_RSZ_CLOCK: - shift = 3; - break; - case VPSS_IPIPE_CLOCK: - shift = 4; - break; - case VPSS_IPIPEIF_CLOCK: - shift = 5; - break; - case VPSS_PCLK_INTERNAL: - shift = 6; - break; - case VPSS_PSYNC_CLOCK_SEL: - shift = 7; - break; - case VPSS_VPBE_CLOCK: - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK: - shift = 3; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_FDIF_CLOCK: - shift = 4; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_OSD_CLOCK_SEL: - shift = 6; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK_SEL: - shift = 7; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - default: - printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", - clock_sel); - return -1; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = read(offset); - if (!en) { - mask = ~mask; - utemp &= (mask << shift); - } else - utemp |= (mask << shift); - - write(utemp, offset); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - - return 0; -} - -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - if (!oper_cfg.hw_ops.enable_clock) - return -EINVAL; - - return oper_cfg.hw_ops.enable_clock(clock_sel, en); -} -EXPORT_SYMBOL(vpss_enable_clock); - -void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) -{ - int val = 0; - val = isp5_read(DM365_ISP5_CCDCMUX); - - val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); - val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); - - isp5_write(val, DM365_ISP5_CCDCMUX); -} -EXPORT_SYMBOL(dm365_vpss_set_sync_pol); - -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) -{ - int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; - - current_reg |= (frame_size.pplen - 1); - isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); -} -EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); - -static int __init vpss_probe(struct platform_device *pdev) -{ - struct resource *r1, *r2; - char *platform_name; - int status; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "no platform data\n"); - return -ENOENT; - } - - platform_name = pdev->dev.platform_data; - if (!strcmp(platform_name, "dm355_vpss")) - oper_cfg.platform = DM355; - else if (!strcmp(platform_name, "dm365_vpss")) - oper_cfg.platform = DM365; - else if (!strcmp(platform_name, "dm644x_vpss")) - oper_cfg.platform = DM644X; - else { - dev_err(&pdev->dev, "vpss driver not supported on" - " this platform\n"); - return -ENODEV; - } - - dev_info(&pdev->dev, "%s vpss probed\n", platform_name); - r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r1) - return -ENOENT; - - r1 = request_mem_region(r1->start, resource_size(r1), r1->name); - if (!r1) - return -EBUSY; - - oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1)); - if (!oper_cfg.vpss_regs_base0) { - status = -EBUSY; - goto fail1; - } - - if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!r2) { - status = -ENOENT; - goto fail2; - } - r2 = request_mem_region(r2->start, resource_size(r2), r2->name); - if (!r2) { - status = -EBUSY; - goto fail2; - } - - oper_cfg.vpss_regs_base1 = ioremap(r2->start, - resource_size(r2)); - if (!oper_cfg.vpss_regs_base1) { - status = -EBUSY; - goto fail3; - } - } - - if (oper_cfg.platform == DM355) { - oper_cfg.hw_ops.enable_clock = dm355_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; - /* Setup vpss interrupts */ - bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); - bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); - } else if (oper_cfg.platform == DM365) { - oper_cfg.hw_ops.enable_clock = dm365_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; - /* Setup vpss interrupts */ - isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); - isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); - isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); - } else - oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; - - spin_lock_init(&oper_cfg.vpss_lock); - dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); - return 0; - -fail3: - release_mem_region(r2->start, resource_size(r2)); -fail2: - iounmap(oper_cfg.vpss_regs_base0); -fail1: - release_mem_region(r1->start, resource_size(r1)); - return status; -} - -static int __devexit vpss_remove(struct platform_device *pdev) -{ - struct resource *res; - - iounmap(oper_cfg.vpss_regs_base0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - iounmap(oper_cfg.vpss_regs_base1); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - release_mem_region(res->start, resource_size(res)); - } - return 0; -} - -static struct platform_driver vpss_driver = { - .driver = { - .name = "vpss", - .owner = THIS_MODULE, - }, - .remove = __devexit_p(vpss_remove), - .probe = vpss_probe, -}; - -static void vpss_exit(void) -{ - platform_driver_unregister(&vpss_driver); -} - -static int __init vpss_init(void) -{ - return platform_driver_register(&vpss_driver); -} -subsys_initcall(vpss_init); -module_exit(vpss_exit); diff --git a/drivers/media/video/ti-media/Kconfig b/drivers/media/video/ti-media/Kconfig new file mode 100644 index 0000000..cda05ef --- /dev/null +++ b/drivers/media/video/ti-media/Kconfig @@ -0,0 +1,100 @@ +config TI_MEDIA + tristate "TI Media Drivers" + depends on VIDEO_V4L2 && (ARCH_OMAP || ARCH_DAVINCI) + default n + ---help--- + Video Drivers for all TI devices, like OMAP, Davinci, etc... + +config DISPLAY_DAVINCI_DM646X_EVM + tristate "DM646x EVM Video Display" + depends on TI_MEDIA && MACH_DAVINCI_DM6467_EVM + select VIDEOBUF_DMA_CONTIG + select VIDEO_DAVINCI_VPIF + select VIDEO_ADV7343 + select VIDEO_THS7303 + help + Support for DM6467 based display device. + + To compile this driver as a module, choose M here: the + module will be called vpif_display. + +config CAPTURE_DAVINCI_DM646X_EVM + tristate "DM646x EVM Video Capture" + depends on TI_MEDIA && MACH_DAVINCI_DM6467_EVM + select VIDEOBUF_DMA_CONTIG + select VIDEO_DAVINCI_VPIF + help + Support for DM6467 based capture device. + + To compile this driver as a module, choose M here: the + module will be called vpif_capture. + +config VIDEO_DAVINCI_VPIF + tristate "DaVinci VPIF Driver" + depends on DISPLAY_DAVINCI_DM646X_EVM + help + Support for DaVinci VPIF Driver. + + To compile this driver as a module, choose M here: the + module will be called vpif. + +config VIDEO_VPSS_SYSTEM + tristate "VPSS System module driver" + depends on TI_MEDIA + help + Support for vpss system module for video driver + +config VIDEO_VPFE_CAPTURE + tristate "VPFE Video Capture Driver" + depends on TI_MEDIA + select VIDEOBUF_DMA_CONTIG + help + 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 vpfe-capture. + +config VIDEO_DM6446_CCDC + tristate "DM6446 CCDC HW module" + depends on VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default n + help + 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 VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default n + 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. + +config VIDEO_ISIF + tristate "ISIF HW module" + depends on VIDEO_VPFE_CAPTURE + select VIDEO_VPSS_SYSTEM + default n + help + Enables ISIF hw module. This is the hardware module for + configuring ISIF in VPFE to capture Raw Bayer RGB data from + a image sensor or YUV data from a YUV source. + + To compile this driver as a module, choose M here: the + module will be called vpfe. diff --git a/drivers/media/video/ti-media/Makefile b/drivers/media/video/ti-media/Makefile new file mode 100644 index 0000000..a379557 --- /dev/null +++ b/drivers/media/video/ti-media/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for the davinci video device drivers. +# + +# VPIF +obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o + +#DM646x EVM Display driver +obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o +#DM646x EVM Capture driver +obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o + +# Capture: DM6446 and DM355 +obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o +obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o +obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o +obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o +obj-$(CONFIG_VIDEO_ISIF) += isif.o diff --git a/drivers/media/video/ti-media/ccdc_hw_device.h b/drivers/media/video/ti-media/ccdc_hw_device.h new file mode 100644 index 0000000..34d7701 --- /dev/null +++ b/drivers/media/video/ti-media/ccdc_hw_device.h @@ -0,0 +1,110 @@ +/* + * 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 + * + * ccdc device API + */ +#ifndef _CCDC_HW_DEVICE_H +#define _CCDC_HW_DEVICE_H + +#ifdef __KERNEL__ +#include +#include +#include +#include + +/* + * ccdc hw operations + */ +struct ccdc_hw_ops { + /* Pointer to initialize function to initialize ccdc device */ + int (*open) (struct device *dev); + /* Pointer to deinitialize function */ + int (*close) (struct device *dev); + /* set ccdc base address */ + void (*set_ccdc_base)(void *base, int size); + /* Pointer to function to enable or disable ccdc */ + void (*enable) (int en); + /* reset sbl. only for 6446 */ + void (*reset) (void); + /* enable output to sdram */ + void (*enable_out_to_sdram) (int en); + /* Pointer to function to set hw parameters */ + int (*set_hw_if_params) (struct vpfe_hw_if_param *param); + /* 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 (*set_params) (void *params); + /* + * Pointer to function to get parameter. Used + * for implementing VPFE_G_CCDC_PARAMS + */ + int (*get_params) (void *params); + /* Pointer to function to configure ccdc */ + int (*configure) (void); + + /* Pointer to function to set buffer type */ + int (*set_buftype) (enum ccdc_buftype buf_type); + /* Pointer to function to get buffer type */ + enum ccdc_buftype (*get_buftype) (void); + /* Pointer to function to set frame format */ + int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); + /* Pointer to function to get frame format */ + enum ccdc_frmfmt (*get_frame_format) (void); + /* enumerate hw pix formats */ + int (*enum_pix)(u32 *hw_pix, int i); + /* Pointer to function to set buffer type */ + u32 (*get_pixel_format) (void); + /* Pointer to function to get pixel format. */ + int (*set_pixel_format) (u32 pixfmt); + /* Pointer to function to set image window */ + int (*set_image_window) (struct v4l2_rect *win); + /* Pointer to function to set image window */ + void (*get_image_window) (struct v4l2_rect *win); + /* Pointer to function to get line length */ + unsigned int (*get_line_length) (void); + + /* Query CCDC control IDs */ + int (*queryctrl)(struct v4l2_queryctrl *qctrl); + /* Set CCDC control */ + int (*set_control)(struct v4l2_control *ctrl); + /* Get CCDC control */ + int (*get_control)(struct v4l2_control *ctrl); + + /* Pointer to function to set frame buffer address */ + void (*setfbaddr) (unsigned long addr); + /* Pointer to function to get field id */ + int (*getfid) (void); +}; + +struct ccdc_hw_device { + /* ccdc device name */ + char name[32]; + /* module owner */ + struct module *owner; + /* hw ops */ + struct ccdc_hw_ops hw_ops; +}; + +/* Used by CCDC module to register & unregister with vpfe capture driver */ +int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); +void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); + +#endif +#endif diff --git a/drivers/media/video/ti-media/dm355_ccdc.c b/drivers/media/video/ti-media/dm355_ccdc.c new file mode 100644 index 0000000..6da4de8 --- /dev/null +++ b/drivers/media/video/ti-media/dm355_ccdc.c @@ -0,0 +1,1086 @@ +/* + * 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 + * + * CCDC hardware module for DM355 + * ------------------------------ + * + * This module is for configuring DM355 CCD controller of VPFE to capture + * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules + * such as Defect Pixel Correction, Color Space Conversion etc to + * pre-process the Bayer RGB data, before writing it to SDRAM. This + * module also allows application to configure individual + * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. + * To do so, application include dm355_ccdc.h and vpfe_capture.h header + * files. The setparams() API is called by vpfe_capture driver + * to configure module parameters + * + * TODO: 1) Raw bayer parameter settings and bayer capture + * 2) Split module parameter structure to module specific ioctl structs + * 3) add support for lense shading correction + * 4) investigate if enum used for user space type definition + * to be replaced by #defines or integer + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "dm355_ccdc_regs.h" +#include "ccdc_hw_device.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CCDC Driver for DM355"); +MODULE_AUTHOR("Texas Instruments"); + +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = 256, + .gb_g = 256, + .gr_cy = 256, + .b_mg = 256 + }, + .config_params = { + .datasft = 2, + .mfilt1 = CCDC_NO_MEDIAN_FILTER1, + .mfilt2 = CCDC_NO_MEDIAN_FILTER2, + .alaw = { + .gama_wd = 2, + }, + .blk_clamp = { + .sample_pixel = 1, + .dc_sub = 25 + }, + .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 + }, + }, + }, + /* YCbCr configuration */ + .ycbcr = { + .win = CCDC_WIN_PAL, + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED + }, +}; + + +/* Raw Bayer formats */ +static u32 ccdc_raw_bayer_pix_formats[] = { + V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_SBGGR16 +}; + +/* Raw YUV formats */ +static u32 ccdc_raw_yuv_pix_formats[] = { + V4L2_PIX_FMT_UYVY, + V4L2_PIX_FMT_YUYV +}; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(ccdc_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, ccdc_cfg.base_addr + offset); +} + +static void ccdc_enable(int en) +{ + unsigned int temp; + temp = regr(SYNCEN); + temp &= (~CCDC_SYNCEN_VDHDEN_MASK); + temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); + regw(temp, SYNCEN); +} + +static void ccdc_enable_output_to_sdram(int en) +{ + unsigned int temp; + temp = regr(SYNCEN); + temp &= (~(CCDC_SYNCEN_WEN_MASK)); + temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); + regw(temp, SYNCEN); +} + +static void ccdc_config_gain_offset(void) +{ + /* configure gain */ + regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); + regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); + regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); + regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); + /* configure offset */ + regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); +} + +/* + * ccdc_restore_defaults() + * This function restore power on defaults in the ccdc registers + */ +static int ccdc_restore_defaults(void) +{ + int i; + + dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); + /* set all registers to zero */ + for (i = 0; i <= CCDC_REG_LAST; i += 4) + regw(0, i); + + /* now override the values with power on defaults in registers */ + regw(MODESET_DEFAULT, MODESET); + /* no culling support */ + regw(CULH_DEFAULT, CULH); + regw(CULV_DEFAULT, CULV); + /* Set default Gain and Offset */ + ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; + ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; + ccdc_config_gain_offset(); + regw(OUTCLIP_DEFAULT, OUTCLIP); + regw(LSCCFG2_DEFAULT, LSCCFG2); + /* select ccdc input */ + if (vpss_select_ccdc_source(VPSS_CCDCIN)) { + dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); + return -EFAULT; + } + /* select ccdc clock */ + if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { + dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); + return -EFAULT; + } + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); + return 0; +} + +static int ccdc_open(struct device *device) +{ + return ccdc_restore_defaults(); +} + +static int ccdc_close(struct device *device) +{ + /* disable clock */ + vpss_enable_clock(VPSS_CCDC_CLOCK, 0); + /* do nothing for now */ + return 0; +} +/* + * ccdc_setwin() + * This function will configure the window size to + * be capture in CCDC reg. + */ +static void ccdc_setwin(struct v4l2_rect *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(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); + + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + 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, SPH); + regw(horz_nr_pixels, NPH); + 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 and VDINT1 */ + regw(vert_start, VDINT0); + } else { + /* Since first line doesn't have any data */ + vert_start += 1; + 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 & CCDC_START_VER_ONE_MASK, SLV0); + regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); + regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); +} + +static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) +{ + if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || + ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { + dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); + return -EINVAL; + } + + if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || + ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); + return -EINVAL; + } + + if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || + ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { + dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); + return -EINVAL; + } + + if ((ccdcparam->med_filt_thres < 0) || + (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { + dev_dbg(ccdc_cfg.dev, + "Invalid value of median filter thresold\n"); + return -EINVAL; + } + + if (ccdcparam->data_sz < CCDC_DATA_16BITS || + ccdcparam->data_sz > CCDC_DATA_8BITS) { + dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); + return -EINVAL; + } + + if (ccdcparam->alaw.enable) { + if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || + ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { + dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); + return -EINVAL; + } + } + + if (ccdcparam->blk_clamp.b_clamp_enable) { + if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || + ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample pixel\n"); + return -EINVAL; + } + if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || + ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { + dev_dbg(ccdc_cfg.dev, + "Invalid value of sample lines\n"); + return -EINVAL; + } + } + return 0; +} + +/* Parameter operations */ +static int ccdc_set_params(void __user *params) +{ + struct ccdc_config_params_raw ccdc_raw_params; + int x; + + /* only raw module parameters can be set through the IOCTL */ + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); + if (x) { + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" + "params, %d\n", x); + return -EFAULT; + } + + if (!validate_ccdc_param(&ccdc_raw_params)) { + memcpy(&ccdc_cfg.bayer.config_params, + &ccdc_raw_params, + sizeof(ccdc_raw_params)); + return 0; + } + return -EINVAL; +} + +/* This function will configure CCDC for YCbCr video capture */ +static void ccdc_config_ycbcr(void) +{ + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; + u32 temp; + + /* first set the CCDC power on defaults values in all registers */ + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); + ccdc_restore_defaults(); + + /* configure pixel format & video frame format */ + temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << + CCDC_INPUT_MODE_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << + CCDC_FRM_FMT_SHIFT)); + + /* setup BT.656 sync mode */ + if (params->bt656_enable) { + regw(CCDC_REC656IF_BT656_EN, REC656IF); + /* + * configure the FID, VD, HD pin polarity fld,hd pol positive, + * vd negative, 8-bit pack mode + */ + temp |= CCDC_VD_POL_NEGATIVE; + } else { /* y/c external sync mode */ + temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << + CCDC_FID_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << + CCDC_HD_POL_SHIFT) | + ((params->vd_pol & CCDC_VD_POL_MASK) << + CCDC_VD_POL_SHIFT)); + } + + /* pack the data to 8-bit */ + temp |= CCDC_DATA_PACK_ENABLE; + + regw(temp, MODESET); + + /* configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 2); + + /* configure the order of y cb cr in SD-RAM */ + temp = (params->pix_order << CCDC_Y8POS_SHIFT); + temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; + regw(temp, 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) >> 5), HSIZE); + + /* configure the memory line offset */ + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { + /* two fields are interleaved in memory */ + regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); + } + + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); +} + +/* + * ccdc_config_black_clamp() + * configure parameters for Optical Black Clamp + */ +static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) +{ + u32 val; + + if (!bclamp->b_clamp_enable) { + /* configure DCSub */ + regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); + regw(0x0000, CLAMP); + return; + } + /* Enable the Black clamping, set sample lines and pixels */ + val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | + ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << + CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; + regw(val, CLAMP); + + /* If Black clamping is enable then make dcsub 0 */ + val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) + << CCDC_NUM_LINE_CALC_SHIFT; + regw(val, DCSUB); +} + +/* + * ccdc_config_black_compense() + * configure parameters for Black Compensation + */ +static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) +{ + u32 val; + + val = (bcomp->b & CCDC_BLK_COMP_MASK) | + ((bcomp->gb & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GB_COMP_SHIFT); + regw(val, BLKCMP1); + + val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GR_COMP_SHIFT) | + ((bcomp->r & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_R_COMP_SHIFT); + regw(val, BLKCMP0); +} + +/* + * ccdc_write_dfc_entry() + * write an entry in the dfc table. + */ +int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) +{ +/* TODO This is to be re-visited and adjusted */ +#define DFC_WRITE_WAIT_COUNT 1000 + u32 val, count = DFC_WRITE_WAIT_COUNT; + + regw(dfc->dft_corr_vert[index], DFCMEM0); + regw(dfc->dft_corr_horz[index], DFCMEM1); + regw(dfc->dft_corr_sub1[index], DFCMEM2); + regw(dfc->dft_corr_sub2[index], DFCMEM3); + regw(dfc->dft_corr_sub3[index], DFCMEM4); + /* set WR bit to write */ + val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; + regw(val, DFCMEMCTL); + + /* + * Assume, it is very short. If we get an error, we need to + * adjust this value + */ + while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) + count--; + /* + * TODO We expect the count to be non-zero to be successful. Adjust + * the count if write requires more time + */ + + if (count) { + dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); + return -1; + } + return 0; +} + +/* + * ccdc_config_vdfc() + * configure parameters for Vertical Defect Correction + */ +static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) +{ + u32 val; + int i; + + /* Configure General Defect Correction. The table used is from IPIPE */ + val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; + + /* Configure Vertical Defect Correction if needed */ + if (!dfc->ver_dft_en) { + /* Enable only General Defect Correction */ + regw(val, DFCCTL); + return 0; + } + + if (dfc->table_size > CCDC_DFT_TABLE_SIZE) + return -EINVAL; + + val |= CCDC_DFCCTL_VDFC_DISABLE; + val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << + CCDC_DFCCTL_VDFCSL_SHIFT; + val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << + CCDC_DFCCTL_VDFCUDA_SHIFT; + val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << + CCDC_DFCCTL_VDFLSFT_SHIFT; + regw(val , DFCCTL); + + /* clear address ptr to offset 0 */ + val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; + + /* write defect table entries */ + for (i = 0; i < dfc->table_size; i++) { + /* increment address for non zero index */ + if (i != 0) + val = CCDC_DFCMEMCTL_INC_ADDR; + regw(val, DFCMEMCTL); + if (ccdc_write_dfc_entry(i, dfc) < 0) + return -EFAULT; + } + + /* update saturation level and enable dfc */ + regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); + val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << + CCDC_DFCCTL_VDFCEN_SHIFT); + regw(val, DFCCTL); + return 0; +} + +/* + * ccdc_config_csc() + * configure parameters for color space conversion + * Each register CSCM0-7 has two values in S8Q5 format. + */ +static void ccdc_config_csc(struct ccdc_csc *csc) +{ + u32 val1, val2; + int i; + + if (!csc->enable) + return; + + /* 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 < CCDC_CSC_COEFF_TABLE_SIZE; i++) { + if ((i % 2) == 0) { + /* CSCM - LSB */ + val1 = (csc->coeff[i].integer & + CCDC_CSC_COEF_INTEG_MASK) + << CCDC_CSC_COEF_INTEG_SHIFT; + /* + * convert decimal part to binary. Use 2 decimal + * precision, user values range from .00 - 0.99 + */ + val1 |= (((csc->coeff[i].decimal & + CCDC_CSC_COEF_DECIMAL_MASK) * + CCDC_CSC_DEC_MAX) / 100); + } else { + + /* CSCM - MSB */ + val2 = (csc->coeff[i].integer & + CCDC_CSC_COEF_INTEG_MASK) + << CCDC_CSC_COEF_INTEG_SHIFT; + val2 |= (((csc->coeff[i].decimal & + CCDC_CSC_COEF_DECIMAL_MASK) * + CCDC_CSC_DEC_MAX) / 100); + val2 <<= CCDC_CSCM_MSB_SHIFT; + val2 |= val1; + regw(val2, (CSCM0 + ((i - 1) << 1))); + } + } +} + +/* + * ccdc_config_color_patterns() + * configure parameters for color patterns + */ +static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, + struct ccdc_col_pat *pat1) +{ + u32 val; + + val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | + (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | + (pat1->elop << 12) | (pat1->elep << 14)); + regw(val, COLPTN); +} + +/* This function will configure CCDC for Raw mode image capture */ +static int ccdc_config_raw(void) +{ + struct ccdc_params_raw *params = &ccdc_cfg.bayer; + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int val; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); + + /* restore power on defaults to register */ + ccdc_restore_defaults(); + + /* CCDCFG register: + * set CCD Not to swap input since input is RAW data + * set FID detection function to Latch at V-Sync + * set WENLOG - ccdc valid area to AND + * set TRGSEL to WENBIT + * set EXTRG to DISABLE + * disable latching function on VSYNC - shadowed registers + */ + regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | + CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | + CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); + + /* + * Set VDHD direction to input, input type to raw input + * normal data polarity, do not use external WEN + */ + val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | + CCDC_EXWEN_DISABLE); + + /* + * Configure the vertical sync polarity (MODESET.VDPOL), horizontal + * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), + * frame format(progressive or interlace), & pixel format (Input mode) + */ + val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | + ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); + + /* set pack for alaw compression */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) + val |= CCDC_DATA_PACK_ENABLE; + + /* Configure for LPF */ + if (config_params->lpf_enable) + val |= (config_params->lpf_enable & CCDC_LPF_MASK) << + CCDC_LPF_SHIFT; + + /* Configure the data shift */ + val |= (config_params->datasft & CCDC_DATASFT_MASK) << + CCDC_DATASFT_SHIFT; + regw(val , MODESET); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); + + /* Configure the Median Filter threshold */ + regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); + + /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ + val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | + CCDC_CFA_MOSAIC; + + /* Enable and configure aLaw register if needed */ + if (config_params->alaw.enable) { + val |= (CCDC_ALAW_ENABLE | + ((config_params->alaw.gama_wd & + CCDC_ALAW_GAMA_WD_MASK) << + CCDC_GAMMAWD_INPUT_SHIFT)); + } + + /* Configure Median filter1 & filter2 */ + val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | + (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); + + regw(val, GAMMAWD); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); + + /* configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 1); + + /* Optical Clamp Averaging */ + ccdc_config_black_clamp(&config_params->blk_clamp); + + /* Black level compensation */ + ccdc_config_black_compense(&config_params->blk_comp); + + /* Vertical Defect Correction if needed */ + if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) + return -EFAULT; + + /* color space conversion */ + ccdc_config_csc(&config_params->csc); + + /* color pattern */ + ccdc_config_color_patterns(&config_params->col_pat_field0, + &config_params->col_pat_field1); + + /* Configure the Gain & offset control */ + ccdc_config_gain_offset(); + + dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); + + /* Configure DATAOFST register */ + val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << + CCDC_DATAOFST_H_SHIFT; + val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << + CCDC_DATAOFST_V_SHIFT; + regw(val, DATAOFST); + + /* configuring HSIZE register */ + 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 ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) { + val |= (((params->win.width) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK; + + /* adjust to multiple of 32 */ + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", + (((params->win.width) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK); + } else { + /* else one pixel will take 2 byte */ + val |= (((params->win.width * 2) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK; + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", + (((params->win.width * 2) + 31) >> 5) & + CCDC_HSIZE_VAL_MASK); + } + regw(val, HSIZE); + + /* Configure SDOFST register */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_enable) { + /* For interlace inverse mode */ + regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_INTERLACE_INVERSE); + } else { + /* For interlace non inverse mode */ + regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_INTERLACE_NORMAL); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + if (params->image_invert_enable) { + /* For progessive inverse mode */ + regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_PROGRESSIVE_INVERSE); + } else { + /* For progessive non inverse mode */ + regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", + CCDC_SDOFST_PROGRESSIVE_NORMAL); + } + } + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); + return 0; +} + +static int ccdc_configure(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_config_raw(); + else + ccdc_config_ycbcr(); + return 0; +} + +static int ccdc_set_buftype(enum ccdc_buftype buf_type) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc_cfg.ycbcr.buf_type = buf_type; + return 0; +} +static enum ccdc_buftype ccdc_get_buftype(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + return ccdc_cfg.ycbcr.buf_type; +} + +static int ccdc_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { + *pix = ccdc_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { + *pix = ccdc_raw_yuv_pix_formats[i]; + ret = 0; + } + } + return ret; +} + +static int ccdc_set_pixel_format(u32 pixfmt) +{ + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + if (pixfmt == V4L2_PIX_FMT_SBGGR8) + alaw->enable = 1; + else if (pixfmt != V4L2_PIX_FMT_SBGGR16) + return -EINVAL; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + } + return 0; +} +static u32 ccdc_get_pixel_format(void) +{ + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; + u32 pixfmt; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + if (alaw->enable) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} +static int ccdc_set_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.win = *win; + else + ccdc_cfg.ycbcr.win = *win; + return 0; +} + +static void ccdc_get_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; + else + *win = ccdc_cfg.ycbcr.win; +} + +static unsigned int ccdc_get_line_length(void) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int len; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if ((config_params->alaw.enable) || + (config_params->data_sz == CCDC_DATA_8BITS)) + len = ccdc_cfg.bayer.win.width; + else + len = ccdc_cfg.bayer.win.width * 2; + } else + len = ccdc_cfg.ycbcr.win.width * 2; + return ALIGN(len, 32); +} + +static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} + +static enum ccdc_frmfmt ccdc_get_frame_format(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; + else + return ccdc_cfg.ycbcr.frm_fmt; +} + +static int ccdc_getfid(void) +{ + return (regr(MODESET) >> 15) & 1; +} + +/* 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_params(struct vpfe_hw_if_param *params) +{ + ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_YCBCR_SYNC_16: + case VPFE_YCBCR_SYNC_8: + ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc_cfg.ycbcr.hd_pol = params->hdpol; + break; + default: + /* TODO add support for raw bayer here */ + return -EINVAL; + } + return 0; +} + +static struct ccdc_hw_device ccdc_hw_dev = { + .name = "DM355 CCDC", + .owner = THIS_MODULE, + .hw_ops = { + .open = ccdc_open, + .close = ccdc_close, + .enable = ccdc_enable, + .enable_out_to_sdram = ccdc_enable_output_to_sdram, + .set_hw_if_params = ccdc_set_hw_if_params, + .set_params = ccdc_set_params, + .configure = ccdc_configure, + .set_buftype = ccdc_set_buftype, + .get_buftype = ccdc_get_buftype, + .enum_pix = ccdc_enum_pix, + .set_pixel_format = ccdc_set_pixel_format, + .get_pixel_format = 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, + }, +}; + +static int __init dm355_ccdc_probe(struct platform_device *pdev) +{ + void (*setup_pinmux)(void); + struct resource *res; + int status = 0; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENODEV; + goto fail_nores; + } + + res = request_mem_region(res->start, resource_size(res), res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); + if (!ccdc_cfg.base_addr) { + status = -ENOMEM; + goto fail_nomem; + } + + /* Get and enable Master clock */ + ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(ccdc_cfg.mclk)) { + status = PTR_ERR(ccdc_cfg.mclk); + goto fail_nomap; + } + if (clk_enable(ccdc_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Get and enable Slave clock */ + ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); + if (IS_ERR(ccdc_cfg.sclk)) { + status = PTR_ERR(ccdc_cfg.sclk); + goto fail_mclk; + } + if (clk_enable(ccdc_cfg.sclk)) { + status = -ENODEV; + goto fail_sclk; + } + + /* Platform data holds setup_pinmux function ptr */ + if (NULL == pdev->dev.platform_data) { + status = -ENODEV; + goto fail_sclk; + } + setup_pinmux = pdev->dev.platform_data; + /* + * setup Mux configuration for ccdc which may be different for + * different SoCs using this CCDC + */ + setup_pinmux(); + ccdc_cfg.dev = &pdev->dev; + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); + return 0; +fail_sclk: + clk_put(ccdc_cfg.sclk); +fail_mclk: + clk_put(ccdc_cfg.mclk); +fail_nomap: + iounmap(ccdc_cfg.base_addr); +fail_nomem: + release_mem_region(res->start, resource_size(res)); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; +} + +static int dm355_ccdc_remove(struct platform_device *pdev) +{ + struct resource *res; + + clk_put(ccdc_cfg.mclk); + clk_put(ccdc_cfg.sclk); + iounmap(ccdc_cfg.base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static struct platform_driver dm355_ccdc_driver = { + .driver = { + .name = "dm355_ccdc", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(dm355_ccdc_remove), + .probe = dm355_ccdc_probe, +}; + +static int __init dm355_ccdc_init(void) +{ + return platform_driver_register(&dm355_ccdc_driver); +} + +static void __exit dm355_ccdc_exit(void) +{ + platform_driver_unregister(&dm355_ccdc_driver); +} + +module_init(dm355_ccdc_init); +module_exit(dm355_ccdc_exit); diff --git a/drivers/media/video/ti-media/dm355_ccdc_regs.h b/drivers/media/video/ti-media/dm355_ccdc_regs.h new file mode 100644 index 0000000..d6d2ef0 --- /dev/null +++ b/drivers/media/video/ti-media/dm355_ccdc_regs.h @@ -0,0 +1,310 @@ +/* + * 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 _DM355_CCDC_REGS_H +#define _DM355_CCDC_REGS_H + +/**************************************************************************\ +* 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 CCDC_REG_LAST DATAOFST +/************************************************************** +* Define for various register bit mask and shifts for CCDC +* +**************************************************************/ +#define CCDC_RAW_IP_MODE 0 +#define CCDC_VDHDOUT_INPUT 0 +#define CCDC_YCINSWP_RAW (0 << 4) +#define CCDC_EXWEN_DISABLE 0 +#define CCDC_DATAPOL_NORMAL 0 +#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 +#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) +#define CCDC_CCDCFG_WENLOG_AND 0 +#define CCDC_CCDCFG_TRGSEL_WEN 0 +#define CCDC_CCDCFG_EXTRG_DISABLE 0 +#define CCDC_CFA_MOSAIC 0 +#define CCDC_Y8POS_SHIFT 11 + +#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 1 +#define CCDC_GAMMAWD_CFA_SHIFT 5 +#define CCDC_GAMMAWD_INPUT_SHIFT 2 +#define CCDC_FID_POL_MASK 1 +#define CCDC_FID_POL_SHIFT 4 +#define CCDC_HD_POL_MASK 1 +#define CCDC_HD_POL_SHIFT 3 +#define CCDC_VD_POL_MASK 1 +#define CCDC_VD_POL_SHIFT 2 +#define CCDC_VD_POL_NEGATIVE (1 << 2) +#define CCDC_FRM_FMT_MASK 1 +#define CCDC_FRM_FMT_SHIFT 7 +#define CCDC_DATA_SZ_MASK 7 +#define CCDC_DATA_SZ_SHIFT 8 +#define CCDC_VDHDOUT_MASK 1 +#define CCDC_VDHDOUT_SHIFT 0 +#define CCDC_EXWEN_MASK 1 +#define CCDC_EXWEN_SHIFT 5 +#define CCDC_INPUT_MODE_MASK 3 +#define CCDC_INPUT_MODE_SHIFT 12 +#define CCDC_PIX_FMT_MASK 3 +#define CCDC_PIX_FMT_SHIFT 12 +#define CCDC_DATAPOL_MASK 1 +#define CCDC_DATAPOL_SHIFT 6 +#define CCDC_WEN_ENABLE (1 << 1) +#define CCDC_VDHDEN_ENABLE (1 << 16) +#define CCDC_LPF_ENABLE (1 << 14) +#define CCDC_ALAW_ENABLE 1 +#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_REC656IF_BT656_EN 3 + +#define CCDC_FMTCFG_FMTMODE_MASK 3 +#define CCDC_FMTCFG_FMTMODE_SHIFT 1 +#define CCDC_FMTCFG_LNUM_MASK 3 +#define CCDC_FMTCFG_LNUM_SHIFT 4 +#define CCDC_FMTCFG_ADDRINC_MASK 7 +#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 1 +#define CCDC_HSIZE_VAL_MASK 0xFFF +#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 +#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D +#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D +#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 +#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 +#define CCDC_START_PX_HOR_MASK 0x7FFF +#define CCDC_NUM_PX_HOR_MASK 0x7FFF +#define CCDC_START_VER_ONE_MASK 0x7FFF +#define CCDC_START_VER_TWO_MASK 0x7FFF +#define CCDC_NUM_LINES_VER 0x7FFF + +#define CCDC_BLK_CLAMP_ENABLE (1 << 15) +#define CCDC_BLK_SGAIN_MASK 0x1F +#define CCDC_BLK_ST_PXL_MASK 0x1FFF +#define CCDC_BLK_SAMPLE_LN_MASK 3 +#define CCDC_BLK_SAMPLE_LN_SHIFT 13 + +#define CCDC_NUM_LINE_CALC_MASK 3 +#define CCDC_NUM_LINE_CALC_SHIFT 14 + +#define CCDC_BLK_DC_SUB_MASK 0x3FFF +#define CCDC_BLK_COMP_MASK 0xFF +#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 (1 << 15) +#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) +#define CCDC_FPC_ENABLE (1 << 15) +#define CCDC_FPC_FPC_NUM_MASK 0x7FFF +#define CCDC_DATA_PACK_ENABLE (1 << 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 0xF + +#define CCDC_CSC_COEF_INTEG_MASK 7 +#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f +#define CCDC_CSC_COEF_INTEG_SHIFT 5 +#define CCDC_CSCM_MSB_SHIFT 8 +#define CCDC_CSC_ENABLE 1 +#define CCDC_CSC_DEC_MAX 32 + +#define CCDC_MFILT1_SHIFT 10 +#define CCDC_MFILT2_SHIFT 8 +#define CCDC_MED_FILT_THRESH 0x3FFF +#define CCDC_LPF_MASK 1 +#define CCDC_LPF_SHIFT 14 +#define CCDC_OFFSET_MASK 0x3FF +#define CCDC_DATASFT_MASK 7 +#define CCDC_DATASFT_SHIFT 8 + +#define CCDC_DF_ENABLE 1 + +#define CCDC_FMTPLEN_P0_MASK 0xF +#define CCDC_FMTPLEN_P1_MASK 0xF +#define CCDC_FMTPLEN_P2_MASK 7 +#define CCDC_FMTPLEN_P3_MASK 7 +#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 0x1FFF +#define CCDC_FMTLNH_MASK 0x1FFF +#define CCDC_FMTSLV_MASK 0x1FFF +#define CCDC_FMTLNV_MASK 0x7FFF +#define CCDC_FMTRLEN_MASK 0x1FFF +#define CCDC_FMTHCNT_MASK 0x1FFF + +#define CCDC_ADP_INIT_MASK 0x1FFF +#define CCDC_ADP_LINE_SHIFT 13 +#define CCDC_ADP_LINE_MASK 3 +#define CCDC_FMTPGN_APTR_MASK 7 + +#define CCDC_DFCCTL_GDFCEN_MASK 1 +#define CCDC_DFCCTL_VDFCEN_MASK 1 +#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) +#define CCDC_DFCCTL_VDFCEN_SHIFT 4 +#define CCDC_DFCCTL_VDFCSL_MASK 3 +#define CCDC_DFCCTL_VDFCSL_SHIFT 5 +#define CCDC_DFCCTL_VDFCUDA_MASK 1 +#define CCDC_DFCCTL_VDFCUDA_SHIFT 7 +#define CCDC_DFCCTL_VDFLSFT_MASK 3 +#define CCDC_DFCCTL_VDFLSFT_SHIFT 8 +#define CCDC_DFCMEMCTL_DFCMARST_MASK 1 +#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 +#define CCDC_DFCMEMCTL_DFCMWR_MASK 1 +#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 +#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) + +#define CCDC_LSCCFG_GFTSF_MASK 7 +#define CCDC_LSCCFG_GFTSF_SHIFT 1 +#define CCDC_LSCCFG_GFTINV_MASK 0xf +#define CCDC_LSCCFG_GFTINV_SHIFT 4 +#define CCDC_LSC_GFTABLE_SEL_MASK 3 +#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 3 +#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 3 +#define CCDC_LSC_FRAC_MASK 0x3FFF +#define CCDC_LSC_CENTRE_MASK 0x3FFF +#define CCDC_LSC_COEF_MASK 0xff +#define CCDC_LSC_COEFL_SHIFT 0 +#define CCDC_LSC_COEFU_SHIFT 8 +#define CCDC_GAIN_MASK 0x7FF +#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) +#define CCDC_SYNCEN_WEN_MASK (1 << 1) +#define CCDC_SYNCEN_WEN_SHIFT 1 + +/* Power on Defaults in hardware */ +#define MODESET_DEFAULT 0x200 +#define CULH_DEFAULT 0xFFFF +#define CULV_DEFAULT 0xFF +#define GAIN_DEFAULT 256 +#define OUTCLIP_DEFAULT 0x3FFF +#define LSCCFG2_DEFAULT 0xE + +#endif diff --git a/drivers/media/video/ti-media/dm644x_ccdc.c b/drivers/media/video/ti-media/dm644x_ccdc.c new file mode 100644 index 0000000..b52e0a0 --- /dev/null +++ b/drivers/media/video/ti-media/dm644x_ccdc.c @@ -0,0 +1,1094 @@ +/* + * 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 + * + * CCDC hardware module for DM6446 + * ------------------------------ + * + * This module is for configuring CCD controller of DM6446 VPFE to capture + * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules + * such as Defect Pixel Correction, Color Space Conversion etc to + * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This + * module also allows application to configure individual + * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. + * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header + * files. The setparams() API is called by vpfe_capture driver + * to configure module parameters. This file is named DM644x so that other + * variants such DM6443 may be supported using the same module. + * + * TODO: Test Raw bayer parameter settings and bayer capture + * Split module parameter structure to module specific ioctl structs + * investigate if enum used for user space type definition + * to be replaced by #defines or integer + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "dm644x_ccdc_regs.h" +#include "ccdc_hw_device.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CCDC Driver for DM6446"); +MODULE_AUTHOR("Texas Instruments"); + +static struct ccdc_oper_config { + struct device *dev; + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* Master clock */ + struct clk *mclk; + /* slave clock */ + struct clk *sclk; + /* ccdc base address */ + void __iomem *base_addr; +} ccdc_cfg = { + /* Raw configurations */ + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = CCDC_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .config_params = { + .data_sz = CCDC_DATA_10BITS, + }, + }, + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = CCDC_WIN_PAL, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .bt656_enable = 1, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED + }, +}; + +#define CCDC_MAX_RAW_YUV_FORMATS 2 + +/* Raw Bayer formats */ +static u32 ccdc_raw_bayer_pix_formats[] = { + V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_SBGGR16 +}; + +/* Raw YUV formats */ +static u32 ccdc_raw_yuv_pix_formats[] = { + V4L2_PIX_FMT_UYVY, + V4L2_PIX_FMT_YUYV +}; + +/* CCDC Save/Restore context */ +static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(ccdc_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, ccdc_cfg.base_addr + offset); +} + +static void ccdc_enable(int flag) +{ + regw(flag, CCDC_PCR); +} + +static void ccdc_enable_vport(int flag) +{ + if (flag) + /* enable video port */ + regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); + else + regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); +} + +/* + * ccdc_setwin() + * This function will configure the window size + * to be capture in CCDC reg + */ +void ccdc_setwin(struct v4l2_rect *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(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + 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, + CCDC_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, CCDC_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, CCDC_VDINT); + + } + regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, + CCDC_VERT_START); + regw(vert_nr_lines, CCDC_VERT_LINES); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); +} + +static void ccdc_readregs(void) +{ + unsigned int val = 0; + + val = regr(CCDC_ALAW); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); + val = regr(CCDC_CLAMP); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); + val = regr(CCDC_DCSUB); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); + val = regr(CCDC_BLKCMP); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); + val = regr(CCDC_FPC_ADDR); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); + val = regr(CCDC_FPC); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); + val = regr(CCDC_FMTCFG); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); + val = regr(CCDC_COLPTN); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); + val = regr(CCDC_FMT_HORZ); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); + val = regr(CCDC_FMT_VERT); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); + val = regr(CCDC_HSIZE_OFF); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); + val = regr(CCDC_SDOFST); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); + val = regr(CCDC_VP_OUT); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); + val = regr(CCDC_SYN_MODE); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); + val = regr(CCDC_HORZ_INFO); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); + val = regr(CCDC_VERT_START); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); + val = regr(CCDC_VERT_LINES); + dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); +} + +static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) +{ + if (ccdcparam->alaw.enable) { + if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || + (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || + (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { + dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); + return -1; + } + } + return 0; +} + +static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int *fpc_virtaddr = NULL; + unsigned int *fpc_physaddr = NULL; + + memcpy(config_params, raw_params, sizeof(*raw_params)); + /* + * allocate memory for fault pixel table and copy the user + * values to the table + */ + if (!config_params->fault_pxl.enable) + return 0; + + fpc_physaddr = (unsigned int *)config_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 != config_params->fault_pxl.fp_num) { + if (fpc_physaddr != NULL) { + free_pages((unsigned long)fpc_physaddr, + get_order + (config_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_dbg(ccdc_cfg.dev, + "\nUnable to allocate memory for FPC"); + return -EFAULT; + } + fpc_physaddr = + (unsigned int *)virt_to_phys((void *)fpc_virtaddr); + } + + /* Copy number of fault pixels and FPC table */ + config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; + if (copy_from_user(fpc_virtaddr, + (void __user *)raw_params->fault_pxl.fpc_table_addr, + config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { + dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); + return -EFAULT; + } + config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; + return 0; +} + +static int ccdc_close(struct device *dev) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; + + fpc_physaddr = (unsigned int *)config_params->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(config_params->fault_pxl.fp_num * + FP_NUM_BYTES)); + } + return 0; +} + +/* + * ccdc_restore_defaults() + * This function will write defaults to all CCDC registers + */ +static void ccdc_restore_defaults(void) +{ + int i; + + /* disable CCDC */ + ccdc_enable(0); + /* set all registers to default value */ + for (i = 4; i <= 0x94; i += 4) + regw(0, i); + regw(CCDC_NO_CULLING, CCDC_CULLING); + regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); +} + +static int ccdc_open(struct device *device) +{ + ccdc_restore_defaults(); + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_enable_vport(1); + return 0; +} + +static void ccdc_sbl_reset(void) +{ + vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); +} + +/* Parameter operations */ +static int ccdc_set_params(void __user *params) +{ + struct ccdc_config_params_raw ccdc_raw_params; + int x; + + if (ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); + if (x) { + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" + "ccdc params, %d\n", x); + return -EFAULT; + } + + if (!validate_ccdc_param(&ccdc_raw_params)) { + if (!ccdc_update_raw_params(&ccdc_raw_params)) + return 0; + } + return -EINVAL; +} + +/* + * ccdc_config_ycbcr() + * This function will configure CCDC for YCbCr video capture + */ +void ccdc_config_ycbcr(void) +{ + struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; + u32 syn_mode; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); + /* + * first restore the CCDC registers to default values + * This is important since we assume default values to be set in + * a lot of registers that we didn't touch + */ + ccdc_restore_defaults(); + + /* + * configure pixel format, frame format, configure video frame + * format, enable output to SDRAM, enable internal timing generator + * and 8bit pack mode + */ + syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << + CCDC_SYN_MODE_INPMOD_SHIFT) | + ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << + CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | + CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); + + /* setup BT.656 sync mode */ + if (params->bt656_enable) { + regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); + + /* + * configure the FID, VD, HD pin polarity, + * fld,hd pol positive, vd negative, 8-bit data + */ + syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; + if (ccdc_cfg.if_type == VPFE_BT656_10BIT) + syn_mode |= CCDC_SYN_MODE_10BITS; + else + syn_mode |= CCDC_SYN_MODE_8BITS; + } else { + /* y/c external sync mode */ + syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << + CCDC_FID_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << + CCDC_HD_POL_SHIFT) | + ((params->vd_pol & CCDC_VD_POL_MASK) << + CCDC_VD_POL_SHIFT)); + } + regw(syn_mode, CCDC_SYN_MODE); + + /* configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, 2); + + /* + * configure the order of y cb cr in SDRAM, and disable latch + * internal register on vsync + */ + if (ccdc_cfg.if_type == VPFE_BT656_10BIT) + regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | + CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, + CCDC_CCDCFG); + else + regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | + CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); + + /* + * configure the horizontal line offset. This should be a + * on 32 byte bondary. So clear LSB 5 bits + */ + regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); + + /* configure the memory line offset */ + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) + /* two fields are interleaved in memory */ + regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); + + ccdc_sbl_reset(); + dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); +} + +static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) +{ + u32 val; + + if (!bclamp->enable) { + /* configure DCSub */ + val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; + regw(val, CCDC_DCSUB); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); + regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); + return; + } + /* + * Configure gain, Start pixel, No of line to be avg, + * No of pixel/line to be avg, & Enable the Black clamping + */ + val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | + ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << + CCDC_BLK_ST_PXL_SHIFT) | + ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << + CCDC_BLK_SAMPLE_LINE_SHIFT) | + ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << + CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); + regw(val, CCDC_CLAMP); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); + /* If Black clamping is enable then make dcsub 0 */ + regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); +} + +static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) +{ + u32 val; + + val = ((bcomp->b & CCDC_BLK_COMP_MASK) | + ((bcomp->gb & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GB_COMP_SHIFT) | + ((bcomp->gr & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_GR_COMP_SHIFT) | + ((bcomp->r & CCDC_BLK_COMP_MASK) << + CCDC_BLK_COMP_R_COMP_SHIFT)); + regw(val, CCDC_BLKCMP); +} + +static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) +{ + u32 val; + + /* Initially disable FPC */ + val = CCDC_FPC_DISABLE; + regw(val, CCDC_FPC); + + if (!fpc->enable) + return; + + /* Configure Fault pixel if needed */ + regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", + (fpc->fpc_table_addr)); + /* Write the FPC params with FPC disable */ + val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; + regw(val, CCDC_FPC); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); + /* read the FPC register */ + val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; + regw(val, CCDC_FPC); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); +} + +/* + * ccdc_config_raw() + * This function will configure CCDC for Raw capture mode + */ +void ccdc_config_raw(void) +{ + struct ccdc_params_raw *params = &ccdc_cfg.bayer; + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int syn_mode = 0; + unsigned int val; + + dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); + + /* Reset CCDC */ + ccdc_restore_defaults(); + + /* Disable latching function registers on VSYNC */ + regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); + + /* + * Configure the vertical sync polarity(SYN_MODE.VDPOL), + * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity + * (SYN_MODE.FLDPOL), frame format(progressive or interlace), + * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output + * SDRAM, enable internal timing generator + */ + syn_mode = + (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | + ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | + ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | + ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | + ((config_params->data_sz & CCDC_DATA_SZ_MASK) << + CCDC_DATA_SZ_SHIFT) | + ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | + CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); + + /* Enable and configure aLaw register if needed */ + if (config_params->alaw.enable) { + val = ((config_params->alaw.gama_wd & + CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); + regw(val, CCDC_ALAW); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); + } + + /* Configure video window */ + ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); + + /* Configure Black Clamp */ + ccdc_config_black_clamp(&config_params->blk_clamp); + + /* Configure Black level compensation */ + ccdc_config_black_compense(&config_params->blk_comp); + + /* Configure Fault Pixel Correction */ + ccdc_config_fpc(&config_params->fault_pxl); + + /* If data size is 8 bit then pack the data */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) + syn_mode |= CCDC_DATA_PACK_ENABLE; + +#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE + /* enable video port */ + val = CCDC_ENABLE_VIDEO_PORT; +#else + /* disable video port */ + val = CCDC_DISABLE_VIDEO_PORT; +#endif + + if (config_params->data_sz == CCDC_DATA_8BITS) + val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) + << CCDC_FMTCFG_VPIN_SHIFT; + else + val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) + << CCDC_FMTCFG_VPIN_SHIFT; + /* Write value in FMTCFG */ + regw(val, CCDC_FMTCFG); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); + /* Configure the color pattern according to mt9t001 sensor */ + regw(CCDC_COLPTN_VAL, CCDC_COLPTN); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); + /* + * Configure Data formatter(Video port) pixel selection + * (FMT_HORZ, FMT_VERT) + */ + val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << + CCDC_FMT_HORZ_FMTSPH_SHIFT) | + (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); + regw(val, CCDC_FMT_HORZ); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); + 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(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", + params->win.height); + regw(val, CCDC_FMT_VERT); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); + + dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); + + /* + * Configure Horizontal offset register. If pack 8 is enabled then + * 1 pixel will take 1 byte + */ + if ((config_params->data_sz == CCDC_DATA_8BITS) || + config_params->alaw.enable) + regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & + CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); + else + /* else one pixel will take 2 byte */ + regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + + CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, + CCDC_HSIZE_OFF); + + /* Set value for SDOFST */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_enable) { + /* For intelace inverse mode */ + regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); + } + + else { + /* For intelace non inverse mode */ + regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); + dev_dbg(ccdc_cfg.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, CCDC_VP_OUT); + + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); + regw(syn_mode, CCDC_SYN_MODE); + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); + + ccdc_sbl_reset(); + dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); + ccdc_readregs(); +} + +static int ccdc_configure(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_config_raw(); + else + ccdc_config_ycbcr(); + return 0; +} + +static int ccdc_set_buftype(enum ccdc_buftype buf_type) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc_cfg.ycbcr.buf_type = buf_type; + return 0; +} + +static enum ccdc_buftype ccdc_get_buftype(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.buf_type; + return ccdc_cfg.ycbcr.buf_type; +} + +static int ccdc_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { + *pix = ccdc_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { + *pix = ccdc_raw_yuv_pix_formats[i]; + ret = 0; + } + } + return ret; +} + +static int ccdc_set_pixel_format(u32 pixfmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + if (pixfmt == V4L2_PIX_FMT_SBGGR8) + ccdc_cfg.bayer.config_params.alaw.enable = 1; + else if (pixfmt != V4L2_PIX_FMT_SBGGR16) + return -EINVAL; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + } + return 0; +} + +static u32 ccdc_get_pixel_format(void) +{ + struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; + u32 pixfmt; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + if (alaw->enable) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} + +static int ccdc_set_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.win = *win; + else + ccdc_cfg.ycbcr.win = *win; + return 0; +} + +static void ccdc_get_image_window(struct v4l2_rect *win) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc_cfg.bayer.win; + else + *win = ccdc_cfg.ycbcr.win; +} + +static unsigned int ccdc_get_line_length(void) +{ + struct ccdc_config_params_raw *config_params = + &ccdc_cfg.bayer.config_params; + unsigned int len; + + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { + if ((config_params->alaw.enable) || + (config_params->data_sz == CCDC_DATA_8BITS)) + len = ccdc_cfg.bayer.win.width; + else + len = ccdc_cfg.bayer.win.width * 2; + } else + len = ccdc_cfg.ycbcr.win.width * 2; + return ALIGN(len, 32); +} + +static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} + +static enum ccdc_frmfmt ccdc_get_frame_format(void) +{ + if (ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc_cfg.bayer.frm_fmt; + else + return ccdc_cfg.ycbcr.frm_fmt; +} + +static int ccdc_getfid(void) +{ + return (regr(CCDC_SYN_MODE) >> 15) & 1; +} + +/* misc operations */ +static inline void ccdc_setfbaddr(unsigned long addr) +{ + regw(addr & 0xffffffe0, CCDC_SDR_ADDR); +} + +static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_YCBCR_SYNC_16: + case VPFE_YCBCR_SYNC_8: + case VPFE_BT656_10BIT: + ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc_cfg.ycbcr.hd_pol = params->hdpol; + break; + default: + /* TODO add support for raw bayer here */ + return -EINVAL; + } + return 0; +} + +static void ccdc_save_context(void) +{ + ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); + ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); + ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); + ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); + ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); + ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); + ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); + ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); + ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); + ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); + ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); + ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); + ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); + ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); + ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); + ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); + ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); + ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); + ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); + ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); + ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); + ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); + ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); + ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); + ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); + ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); + ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); + ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); + ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); + ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); + ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); + ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); + ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); + ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); + ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); + ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); + ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); +} + +static void ccdc_restore_context(void) +{ + regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); + regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); + regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); + regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); + regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); + regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); + regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); + regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); + regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); + regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); + regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); + regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); + regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); + regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); + regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); + regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); + regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); + regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); + regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); + regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); + regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); + regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); + regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); + regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); + regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); + regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); + regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); + regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); + regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); + regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); + regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); + regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); + regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); + regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); + regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); + regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); + regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); +} +static struct ccdc_hw_device ccdc_hw_dev = { + .name = "DM6446 CCDC", + .owner = THIS_MODULE, + .hw_ops = { + .open = ccdc_open, + .close = ccdc_close, + .reset = ccdc_sbl_reset, + .enable = ccdc_enable, + .set_hw_if_params = ccdc_set_hw_if_params, + .set_params = ccdc_set_params, + .configure = ccdc_configure, + .set_buftype = ccdc_set_buftype, + .get_buftype = ccdc_get_buftype, + .enum_pix = ccdc_enum_pix, + .set_pixel_format = ccdc_set_pixel_format, + .get_pixel_format = 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, + }, +}; + +static int __init dm644x_ccdc_probe(struct platform_device *pdev) +{ + struct resource *res; + int status = 0; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&ccdc_hw_dev); + if (status < 0) + return status; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + status = -ENODEV; + goto fail_nores; + } + + res = request_mem_region(res->start, resource_size(res), res->name); + if (!res) { + status = -EBUSY; + goto fail_nores; + } + + ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); + if (!ccdc_cfg.base_addr) { + status = -ENOMEM; + goto fail_nomem; + } + + /* Get and enable Master clock */ + ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(ccdc_cfg.mclk)) { + status = PTR_ERR(ccdc_cfg.mclk); + goto fail_nomap; + } + if (clk_enable(ccdc_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Get and enable Slave clock */ + ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); + if (IS_ERR(ccdc_cfg.sclk)) { + status = PTR_ERR(ccdc_cfg.sclk); + goto fail_mclk; + } + if (clk_enable(ccdc_cfg.sclk)) { + status = -ENODEV; + goto fail_sclk; + } + ccdc_cfg.dev = &pdev->dev; + printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); + return 0; +fail_sclk: + clk_put(ccdc_cfg.sclk); +fail_mclk: + clk_put(ccdc_cfg.mclk); +fail_nomap: + iounmap(ccdc_cfg.base_addr); +fail_nomem: + release_mem_region(res->start, resource_size(res)); +fail_nores: + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return status; +} + +static int dm644x_ccdc_remove(struct platform_device *pdev) +{ + struct resource *res; + + clk_put(ccdc_cfg.mclk); + clk_put(ccdc_cfg.sclk); + iounmap(ccdc_cfg.base_addr); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + vpfe_unregister_ccdc_device(&ccdc_hw_dev); + return 0; +} + +static int dm644x_ccdc_suspend(struct device *dev) +{ + /* Save CCDC context */ + ccdc_save_context(); + /* Disable CCDC */ + ccdc_enable(0); + /* Disable both master and slave clock */ + clk_disable(ccdc_cfg.mclk); + clk_disable(ccdc_cfg.sclk); + + return 0; +} + +static int dm644x_ccdc_resume(struct device *dev) +{ + /* Enable both master and slave clock */ + clk_enable(ccdc_cfg.mclk); + clk_enable(ccdc_cfg.sclk); + /* Restore CCDC context */ + ccdc_restore_context(); + + return 0; +} + +static const struct dev_pm_ops dm644x_ccdc_pm_ops = { + .suspend = dm644x_ccdc_suspend, + .resume = dm644x_ccdc_resume, +}; + +static struct platform_driver dm644x_ccdc_driver = { + .driver = { + .name = "dm644x_ccdc", + .owner = THIS_MODULE, + .pm = &dm644x_ccdc_pm_ops, + }, + .remove = __devexit_p(dm644x_ccdc_remove), + .probe = dm644x_ccdc_probe, +}; + +static int __init dm644x_ccdc_init(void) +{ + return platform_driver_register(&dm644x_ccdc_driver); +} + +static void __exit dm644x_ccdc_exit(void) +{ + platform_driver_unregister(&dm644x_ccdc_driver); +} + +module_init(dm644x_ccdc_init); +module_exit(dm644x_ccdc_exit); diff --git a/drivers/media/video/ti-media/dm644x_ccdc_regs.h b/drivers/media/video/ti-media/dm644x_ccdc_regs.h new file mode 100644 index 0000000..90370e4 --- /dev/null +++ b/drivers/media/video/ti-media/dm644x_ccdc_regs.h @@ -0,0 +1,153 @@ +/* + * 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 _DM644X_CCDC_REGS_H +#define _DM644X_CCDC_REGS_H + +/**************************************************************************\ +* Register OFFSET Definitions +\**************************************************************************/ +#define CCDC_PID 0x0 +#define CCDC_PCR 0x4 +#define CCDC_SYN_MODE 0x8 +#define CCDC_HD_VD_WID 0xc +#define CCDC_PIX_LINES 0x10 +#define CCDC_HORZ_INFO 0x14 +#define CCDC_VERT_START 0x18 +#define CCDC_VERT_LINES 0x1c +#define CCDC_CULLING 0x20 +#define CCDC_HSIZE_OFF 0x24 +#define CCDC_SDOFST 0x28 +#define CCDC_SDR_ADDR 0x2c +#define CCDC_CLAMP 0x30 +#define CCDC_DCSUB 0x34 +#define CCDC_COLPTN 0x38 +#define CCDC_BLKCMP 0x3c +#define CCDC_FPC 0x40 +#define CCDC_FPC_ADDR 0x44 +#define CCDC_VDINT 0x48 +#define CCDC_ALAW 0x4c +#define CCDC_REC656IF 0x50 +#define CCDC_CCDCFG 0x54 +#define CCDC_FMTCFG 0x58 +#define CCDC_FMT_HORZ 0x5c +#define CCDC_FMT_VERT 0x60 +#define CCDC_FMT_ADDR0 0x64 +#define CCDC_FMT_ADDR1 0x68 +#define CCDC_FMT_ADDR2 0x6c +#define CCDC_FMT_ADDR3 0x70 +#define CCDC_FMT_ADDR4 0x74 +#define CCDC_FMT_ADDR5 0x78 +#define CCDC_FMT_ADDR6 0x7c +#define CCDC_FMT_ADDR7 0x80 +#define CCDC_PRGEVEN_0 0x84 +#define CCDC_PRGEVEN_1 0x88 +#define CCDC_PRGODD_0 0x8c +#define CCDC_PRGODD_1 0x90 +#define CCDC_VP_OUT 0x94 +#define CCDC_REG_END 0x98 + +/*************************************************************** +* Define for various register bit mask and shifts for CCDC +****************************************************************/ +#define CCDC_FID_POL_MASK 1 +#define CCDC_FID_POL_SHIFT 4 +#define CCDC_HD_POL_MASK 1 +#define CCDC_HD_POL_SHIFT 3 +#define CCDC_VD_POL_MASK 1 +#define CCDC_VD_POL_SHIFT 2 +#define CCDC_HSIZE_OFF_MASK 0xffffffe0 +#define CCDC_32BYTE_ALIGN_VAL 31 +#define CCDC_FRM_FMT_MASK 0x1 +#define CCDC_FRM_FMT_SHIFT 7 +#define CCDC_DATA_SZ_MASK 7 +#define CCDC_DATA_SZ_SHIFT 8 +#define CCDC_PIX_FMT_MASK 3 +#define CCDC_PIX_FMT_SHIFT 12 +#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF +#define CCDC_WEN_ENABLE (1 << 17) +#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF +#define CCDC_VDHDEN_ENABLE (1 << 16) +#define CCDC_LPF_ENABLE (1 << 14) +#define CCDC_ALAW_ENABLE (1 << 3) +#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_BLK_CLAMP_ENABLE (1 << 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 7 +#define CCDC_BLK_SAMPLE_LN_SHIFT 28 +#define CCDC_BLK_SAMPLE_LINE_MASK 7 +#define CCDC_BLK_SAMPLE_LINE_SHIFT 25 +#define CCDC_BLK_DC_SUB_MASK 0x03FFF +#define CCDC_BLK_COMP_MASK 0xFF +#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 (1 << 15) +#define CCDC_FPC_ENABLE (1 << 15) +#define CCDC_FPC_DISABLE 0 +#define CCDC_FPC_FPC_NUM_MASK 0x7FFF +#define CCDC_DATA_PACK_ENABLE (1 << 11) +#define CCDC_FMTCFG_VPIN_MASK 7 +#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 0xF +#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 +#define CCDC_PPC_RAW 1 +#define CCDC_DCSUB_DEFAULT_VAL 0 +#define CCDC_CLAMP_DEFAULT_VAL 0 +#define CCDC_ENABLE_VIDEO_PORT 0x8000 +#define CCDC_DISABLE_VIDEO_PORT 0 +#define CCDC_COLPTN_VAL 0xBB11BB11 +#define CCDC_TWO_BYTES_PER_PIXEL 2 +#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D +#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 +#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 +#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 +#define CCDC_INTERLACED_HEIGHT_SHIFT 1 +#define CCDC_SYN_MODE_INPMOD_SHIFT 12 +#define CCDC_SYN_MODE_INPMOD_MASK 3 +#define CCDC_SYN_MODE_8BITS (7 << 8) +#define CCDC_SYN_MODE_10BITS (6 << 8) +#define CCDC_SYN_MODE_11BITS (5 << 8) +#define CCDC_SYN_MODE_12BITS (4 << 8) +#define CCDC_SYN_MODE_13BITS (3 << 8) +#define CCDC_SYN_MODE_14BITS (2 << 8) +#define CCDC_SYN_MODE_15BITS (1 << 8) +#define CCDC_SYN_MODE_16BITS (0 << 8) +#define CCDC_SYN_FLDMODE_MASK 1 +#define CCDC_SYN_FLDMODE_SHIFT 7 +#define CCDC_REC656IF_BT656_EN 3 +#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define CCDC_CCDCFG_Y8POS_SHIFT 11 +#define CCDC_CCDCFG_BW656_10BIT (1 << 5) +#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 +#define CCDC_NO_CULLING 0xffff00ff +#endif diff --git a/drivers/media/video/ti-media/isif.c b/drivers/media/video/ti-media/isif.c new file mode 100644 index 0000000..6542430 --- /dev/null +++ b/drivers/media/video/ti-media/isif.c @@ -0,0 +1,1172 @@ +/* + * 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 + * + * Image Sensor Interface (ISIF) driver + * + * This driver is for configuring the ISIF IP available on DM365 or any other + * TI SoCs. This is used for capturing yuv or bayer video or image data + * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 + * and DM6446, but with enhanced or additional ip blocks. The driver + * configures the ISIF upon commands from the vpfe bridge driver through + * ccdc_hw_device interface. + * + * TODO: 1) Raw bayer parameter settings and bayer capture + * 2) Add support for control ioctl + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "isif_regs.h" +#include "ccdc_hw_device.h" + +/* Defaults for module configuration parameters */ +static struct isif_config_params_raw isif_config_defaults = { + .linearize = { + .en = 0, + .corr_shft = ISIF_NO_SHIFT, + .scale_fact = {1, 0}, + }, + .df_csc = { + .df_or_csc = 0, + .csc = { + .en = 0, + }, + }, + .dfc = { + .en = 0, + }, + .bclamp = { + .en = 0, + }, + .gain_offset = { + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + }, + .culling = { + .hcpat_odd = 0xff, + .hcpat_even = 0xff, + .vcpat = 0xff, + }, + .compress = { + .alg = ISIF_ALAW, + }, +}; + +/* ISIF operation configuration */ +static struct isif_oper_config { + struct device *dev; + enum vpfe_hw_if_type if_type; + struct isif_ycbcr_config ycbcr; + struct isif_params_raw bayer; + enum isif_data_pack data_pack; + /* Master clock */ + struct clk *mclk; + /* ISIF base address */ + void __iomem *base_addr; + /* ISIF Linear Table 0 */ + void __iomem *linear_tbl0_addr; + /* ISIF Linear Table 1 */ + void __iomem *linear_tbl1_addr; +} isif_cfg = { + .ycbcr = { + .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, + .frm_fmt = CCDC_FRMFMT_INTERLACED, + .win = ISIF_WIN_NTSC, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .pix_order = CCDC_PIXORDER_CBYCRY, + .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, + }, + .bayer = { + .pix_fmt = CCDC_PIXFMT_RAW, + .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, + .win = ISIF_WIN_VGA, + .fid_pol = VPFE_PINPOL_POSITIVE, + .vd_pol = VPFE_PINPOL_POSITIVE, + .hd_pol = VPFE_PINPOL_POSITIVE, + .gain = { + .r_ye = {1, 0}, + .gr_cy = {1, 0}, + .gb_g = {1, 0}, + .b_mg = {1, 0}, + }, + .cfa_pat = ISIF_CFA_PAT_MOSAIC, + .data_msb = ISIF_BIT_MSB_11, + .config_params = { + .data_shift = ISIF_NO_SHIFT, + .col_pat_field0 = { + .olop = ISIF_GREEN_BLUE, + .olep = ISIF_BLUE, + .elop = ISIF_RED, + .elep = ISIF_GREEN_RED, + }, + .col_pat_field1 = { + .olop = ISIF_GREEN_BLUE, + .olep = ISIF_BLUE, + .elop = ISIF_RED, + .elep = ISIF_GREEN_RED, + }, + .test_pat_gen = 0, + }, + }, + .data_pack = ISIF_DATA_PACK8, +}; + +/* Raw Bayer formats */ +static const u32 isif_raw_bayer_pix_formats[] = { + V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; + +/* Raw YUV formats */ +static const u32 isif_raw_yuv_pix_formats[] = { + V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; + +/* register access routines */ +static inline u32 regr(u32 offset) +{ + return __raw_readl(isif_cfg.base_addr + offset); +} + +static inline void regw(u32 val, u32 offset) +{ + __raw_writel(val, isif_cfg.base_addr + offset); +} + +/* reg_modify() - read, modify and write register */ +static inline u32 reg_modify(u32 mask, u32 val, u32 offset) +{ + u32 new_val = (regr(offset) & ~mask) | (val & mask); + + regw(new_val, offset); + return new_val; +} + +static inline void regw_lin_tbl(u32 val, u32 offset, int i) +{ + if (!i) + __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); + else + __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); +} + +static void isif_disable_all_modules(void) +{ + /* disable BC */ + regw(0, CLAMPCFG); + /* disable vdfc */ + regw(0, DFCCTL); + /* disable CSC */ + regw(0, CSCCTL); + /* disable linearization */ + regw(0, LINCFG0); + /* disable other modules here as they are supported */ +} + +static void isif_enable(int en) +{ + if (!en) { + /* Before disable isif, disable all ISIF modules */ + isif_disable_all_modules(); + /* + * wait for next VD. Assume lowest scan rate is 12 Hz. So + * 100 msec delay is good enough + */ + msleep(100); + } + reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); +} + +static void isif_enable_output_to_sdram(int en) +{ + reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); +} + +static void isif_config_culling(struct isif_cul *cul) +{ + u32 val; + + /* Horizontal pattern */ + val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; + regw(val, CULH); + + /* vertical pattern */ + regw(cul->vcpat, CULV); + + /* LPF */ + reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, + cul->en_lpf << ISIF_LPF_SHIFT, MODESET); +} + +static void isif_config_gain_offset(void) +{ + struct isif_gain_offsets_adj *gain_off_p = + &isif_cfg.bayer.config_params.gain_offset; + u32 val; + + val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | + (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | + (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | + (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | + (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | + (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); + + reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); + + val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.r_ye.decimal; + regw(val, CRGAIN); + + val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.gr_cy.decimal; + regw(val, CGRGAIN); + + val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.gb_g.decimal; + regw(val, CGBGAIN); + + val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | + gain_off_p->gain.b_mg.decimal; + regw(val, CBGAIN); + + regw(gain_off_p->offset, COFSTA); +} + +static void isif_restore_defaults(void) +{ + enum vpss_ccdc_source_sel source = VPSS_CCDCIN; + + dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); + isif_cfg.bayer.config_params = isif_config_defaults; + /* Enable clock to ISIF, IPIPEIF and BL */ + vpss_enable_clock(VPSS_CCDC_CLOCK, 1); + vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); + vpss_enable_clock(VPSS_BL_CLOCK, 1); + /* Set default offset and gain */ + isif_config_gain_offset(); + vpss_select_ccdc_source(source); + dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); +} + +static int isif_open(struct device *device) +{ + isif_restore_defaults(); + return 0; +} + +/* This function will configure the window size to be capture in ISIF reg */ +static void isif_setwin(struct v4l2_rect *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(isif_cfg.dev, "\nStarting isif_setwin..."); + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + 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, LNH); + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + } else { + /* To account for VD since line 0 doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* configure VDINT0 and VDINT1 */ + mid_img = vert_start + (image_win->height / 2); + regw(mid_img, VDINT1); + } + + regw(0, VDINT0); + regw(vert_start & START_VER_ONE_MASK, SLV0); + regw(vert_start & START_VER_TWO_MASK, SLV1); + regw(vert_nr_lines & NUM_LINES_VER, LNV); +} + +static void isif_config_bclamp(struct isif_black_clamp *bc) +{ + u32 val; + + /* + * DC Offset is always added to image data irrespective of bc enable + * status + */ + regw(bc->dc_offset, CLDCOFST); + + if (bc->en) { + val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; + + /* Enable BC and horizontal clamp caculation paramaters */ + val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); + + regw(val, CLAMPCFG); + + if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { + /* + * Window count for calculation + * Base window selection + * pixel limit + * Horizontal size of window + * vertical size of the window + * Horizontal start position of the window + * Vertical start position of the window + */ + val = bc->horz.win_count_calc | + ((!!bc->horz.base_win_sel_calc) << + ISIF_HORZ_BC_WIN_SEL_SHIFT) | + ((!!bc->horz.clamp_pix_limit) << + ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | + (bc->horz.win_h_sz_calc << + ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | + (bc->horz.win_v_sz_calc << + ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); + regw(val, CLHWIN0); + + regw(bc->horz.win_start_h_calc, CLHWIN1); + regw(bc->horz.win_start_v_calc, CLHWIN2); + } + + /* vertical clamp caculation paramaters */ + + /* Reset clamp value sel for previous line */ + val |= + (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | + (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); + regw(val, CLVWIN0); + + /* Optical Black horizontal start position */ + regw(bc->vert.ob_start_h, CLVWIN1); + /* Optical Black vertical start position */ + regw(bc->vert.ob_start_v, CLVWIN2); + /* Optical Black vertical size for calculation */ + regw(bc->vert.ob_v_sz_calc, CLVWIN3); + /* Vertical start position for BC subtraction */ + regw(bc->vert_start_sub, CLSV); + } +} + +static void isif_config_linearization(struct isif_linearize *linearize) +{ + u32 val, i; + + if (!linearize->en) { + regw(0, LINCFG0); + return; + } + + /* shift value for correction & enable linearization (set lsb) */ + val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; + regw(val, LINCFG0); + + /* Scale factor */ + val = ((!!linearize->scale_fact.integer) << + ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | + linearize->scale_fact.decimal; + regw(val, LINCFG1); + + for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { + if (i % 2) + regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); + else + regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); + } +} + +static int isif_config_dfc(struct isif_dfc *vdfc) +{ + /* initialize retries to loop for max ~ 250 usec */ + u32 val, count, retries = loops_per_jiffy / (4000/HZ); + int i; + + if (!vdfc->en) + return 0; + + /* Correction mode */ + val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); + + /* Correct whole line or partial */ + if (vdfc->corr_whole_line) + val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; + + /* level shift value */ + val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; + + regw(val, DFCCTL); + + /* Defect saturation level */ + regw(vdfc->def_sat_level, VDFSATLV); + + regw(vdfc->table[0].pos_vert, DFCMEM0); + regw(vdfc->table[0].pos_horz, DFCMEM1); + if (vdfc->corr_mode == ISIF_VDFC_NORMAL || + vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[0].level_at_pos, DFCMEM2); + regw(vdfc->table[0].level_up_pixels, DFCMEM3); + regw(vdfc->table[0].level_low_pixels, DFCMEM4); + } + + /* set DFCMARST and set DFCMWR */ + val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; + regw(val, DFCMEMCTL); + + count = retries; + while (count && (regr(DFCMEMCTL) & 0x1)) + count--; + + if (!count) { + dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); + return -1; + } + + for (i = 1; i < vdfc->num_vdefects; i++) { + regw(vdfc->table[i].pos_vert, DFCMEM0); + regw(vdfc->table[i].pos_horz, DFCMEM1); + if (vdfc->corr_mode == ISIF_VDFC_NORMAL || + vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { + regw(vdfc->table[i].level_at_pos, DFCMEM2); + regw(vdfc->table[i].level_up_pixels, DFCMEM3); + regw(vdfc->table[i].level_low_pixels, DFCMEM4); + } + val = regr(DFCMEMCTL); + /* clear DFCMARST and set DFCMWR */ + val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); + val |= 1; + regw(val, DFCMEMCTL); + + count = retries; + while (count && (regr(DFCMEMCTL) & 0x1)) + count--; + + if (!count) { + dev_err(isif_cfg.dev, + "defect table write timeout !!!\n"); + return -1; + } + } + if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { + /* Extra cycle needed */ + regw(0, DFCMEM0); + regw(0x1FFF, DFCMEM1); + regw(1, DFCMEMCTL); + } + + /* enable VDFC */ + reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), + DFCCTL); + return 0; +} + +static void isif_config_csc(struct isif_df_csc *df_csc) +{ + u32 val1 = 0, val2 = 0, i; + + if (!df_csc->csc.en) { + regw(0, CSCCTL); + return; + } + for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { + if ((i % 2) == 0) { + /* CSCM - LSB */ + val1 = (df_csc->csc.coeff[i].integer << + ISIF_CSC_COEF_INTEG_SHIFT) | + df_csc->csc.coeff[i].decimal; + } else { + + /* CSCM - MSB */ + val2 = (df_csc->csc.coeff[i].integer << + ISIF_CSC_COEF_INTEG_SHIFT) | + df_csc->csc.coeff[i].decimal; + val2 <<= ISIF_CSCM_MSB_SHIFT; + val2 |= val1; + regw(val2, (CSCM0 + ((i - 1) << 1))); + } + } + + /* program the active area */ + regw(df_csc->start_pix, FMTSPH); + /* + * one extra pixel as required for CSC. Actually number of + * pixel - 1 should be configured in this register. So we + * need to subtract 1 before writing to FMTSPH, but we will + * not do this since csc requires one extra pixel + */ + regw(df_csc->num_pixels, FMTLNH); + regw(df_csc->start_line, FMTSLV); + /* + * one extra line as required for CSC. See reason documented for + * num_pixels + */ + regw(df_csc->num_lines, FMTLNV); + + /* Enable CSC */ + regw(1, CSCCTL); +} + +static int isif_config_raw(void) +{ + struct isif_params_raw *params = &isif_cfg.bayer; + struct isif_config_params_raw *module_params = + &isif_cfg.bayer.config_params; + struct vpss_pg_frame_size frame_size; + struct vpss_sync_pol sync; + u32 val; + + dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); + + /* + * Configure CCDCFG register:- + * Set CCD Not to swap input since input is RAW data + * Set FID detection function to Latch at V-Sync + * Set WENLOG - isif valid area + * Set TRGSEL + * Set EXTRG + * Packed to 8 or 16 bits + */ + + val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | + ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | + ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; + + dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); + regw(val, CCDCFG); + + /* + * Configure the vertical sync polarity(MODESET.VDPOL) + * Configure the horizontal sync polarity (MODESET.HDPOL) + * Configure frame id polarity (MODESET.FLDPOL) + * Configure data polarity + * Configure External WEN Selection + * Configure frame format(progressive or interlace) + * Configure pixel format (Input mode) + * Configure the data shift + */ + + val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | + (params->hd_pol << ISIF_HD_POL_SHIFT) | + (params->fid_pol << ISIF_FID_POL_SHIFT) | + (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | + (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | + (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | + (params->pix_fmt << ISIF_INPUT_SHIFT) | + (params->config_params.data_shift << ISIF_DATASFT_SHIFT); + + regw(val, MODESET); + dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); + + /* + * Configure GAMMAWD register + * CFA pattern setting + */ + val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; + + /* Gamma msb */ + if (module_params->compress.alg == ISIF_ALAW) + val |= ISIF_ALAW_ENABLE; + + val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); + regw(val, CGAMMAWD); + + /* Configure DPCM compression settings */ + if (module_params->compress.alg == ISIF_DPCM) { + val = BIT(ISIF_DPCM_EN_SHIFT) | + (module_params->compress.pred << + ISIF_DPCM_PREDICTOR_SHIFT); + } + + regw(val, MISC); + + /* Configure Gain & Offset */ + isif_config_gain_offset(); + + /* Configure Color pattern */ + val = (params->config_params.col_pat_field0.olop) | + (params->config_params.col_pat_field0.olep << 2) | + (params->config_params.col_pat_field0.elop << 4) | + (params->config_params.col_pat_field0.elep << 6) | + (params->config_params.col_pat_field1.olop << 8) | + (params->config_params.col_pat_field1.olep << 10) | + (params->config_params.col_pat_field1.elop << 12) | + (params->config_params.col_pat_field1.elep << 14); + regw(val, CCOLP); + dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); + + /* Configure HSIZE register */ + val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; + + /* calculate line offset in 32 bytes based on pack value */ + if (isif_cfg.data_pack == ISIF_PACK_8BIT) + val |= ((params->win.width + 31) >> 5); + else if (isif_cfg.data_pack == ISIF_PACK_12BIT) + val |= (((params->win.width + + (params->win.width >> 2)) + 31) >> 5); + else + val |= (((params->win.width * 2) + 31) >> 5); + regw(val, HSIZE); + + /* Configure SDOFST register */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_en) { + /* For interlace inverse mode */ + regw(0x4B6D, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); + } else { + /* For interlace non inverse mode */ + regw(0x0B6D, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + if (params->image_invert_en) { + /* For progressive inverse mode */ + regw(0x4000, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); + } else { + /* For progressive non inverse mode */ + regw(0x0000, SDOFST); + dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); + } + } + + /* Configure video window */ + isif_setwin(¶ms->win, params->frm_fmt, 1); + + /* Configure Black Clamp */ + isif_config_bclamp(&module_params->bclamp); + + /* Configure Vertical Defection Pixel Correction */ + if (isif_config_dfc(&module_params->dfc) < 0) + return -EFAULT; + + if (!module_params->df_csc.df_or_csc) + /* Configure Color Space Conversion */ + isif_config_csc(&module_params->df_csc); + + isif_config_linearization(&module_params->linearize); + + /* Configure Culling */ + isif_config_culling(&module_params->culling); + + /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ + regw(module_params->horz_offset, DATAHOFST); + regw(module_params->vert_offset, DATAVOFST); + + /* Setup test pattern if enabled */ + if (params->config_params.test_pat_gen) { + /* Use the HD/VD pol settings from user */ + sync.ccdpg_hdpol = params->hd_pol; + sync.ccdpg_vdpol = params->vd_pol; + dm365_vpss_set_sync_pol(sync); + frame_size.hlpfr = isif_cfg.bayer.win.width; + frame_size.pplen = isif_cfg.bayer.win.height; + dm365_vpss_set_pg_frame_size(frame_size); + vpss_select_ccdc_source(VPSS_PGLPBK); + } + + dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); + return 0; +} + +static int isif_set_buftype(enum ccdc_buftype buf_type) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + isif_cfg.bayer.buf_type = buf_type; + else + isif_cfg.ycbcr.buf_type = buf_type; + + return 0; + +} +static enum ccdc_buftype isif_get_buftype(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_cfg.bayer.buf_type; + + return isif_cfg.ycbcr.buf_type; +} + +static int isif_enum_pix(u32 *pix, int i) +{ + int ret = -EINVAL; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { + *pix = isif_raw_bayer_pix_formats[i]; + ret = 0; + } + } else { + if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { + *pix = isif_raw_yuv_pix_formats[i]; + ret = 0; + } + } + + return ret; +} + +static int isif_set_pixel_format(unsigned int pixfmt) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (pixfmt == V4L2_PIX_FMT_SBGGR8) { + if ((isif_cfg.bayer.config_params.compress.alg != + ISIF_ALAW) && + (isif_cfg.bayer.config_params.compress.alg != + ISIF_DPCM)) { + dev_dbg(isif_cfg.dev, + "Either configure A-Law or DPCM\n"); + return -EINVAL; + } + isif_cfg.data_pack = ISIF_PACK_8BIT; + } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { + isif_cfg.bayer.config_params.compress.alg = + ISIF_NO_COMPRESSION; + isif_cfg.data_pack = ISIF_PACK_16BIT; + } else + return -EINVAL; + isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + } else { + if (pixfmt == V4L2_PIX_FMT_YUYV) + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + else if (pixfmt == V4L2_PIX_FMT_UYVY) + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + else + return -EINVAL; + isif_cfg.data_pack = ISIF_PACK_8BIT; + } + return 0; +} + +static u32 isif_get_pixel_format(void) +{ + u32 pixfmt; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) + if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || + isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) + pixfmt = V4L2_PIX_FMT_SBGGR8; + else + pixfmt = V4L2_PIX_FMT_SBGGR16; + else { + if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + return pixfmt; +} + +static int isif_set_image_window(struct v4l2_rect *win) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + isif_cfg.bayer.win.top = win->top; + isif_cfg.bayer.win.left = win->left; + isif_cfg.bayer.win.width = win->width; + isif_cfg.bayer.win.height = win->height; + } else { + isif_cfg.ycbcr.win.top = win->top; + isif_cfg.ycbcr.win.left = win->left; + isif_cfg.ycbcr.win.width = win->width; + isif_cfg.ycbcr.win.height = win->height; + } + return 0; +} + +static void isif_get_image_window(struct v4l2_rect *win) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + *win = isif_cfg.bayer.win; + else + *win = isif_cfg.ycbcr.win; +} + +static unsigned int isif_get_line_length(void) +{ + unsigned int len; + + if (isif_cfg.if_type == VPFE_RAW_BAYER) { + if (isif_cfg.data_pack == ISIF_PACK_8BIT) + len = ((isif_cfg.bayer.win.width)); + else if (isif_cfg.data_pack == ISIF_PACK_12BIT) + len = (((isif_cfg.bayer.win.width * 2) + + (isif_cfg.bayer.win.width >> 2))); + else + len = (((isif_cfg.bayer.win.width * 2))); + } else + len = (((isif_cfg.ycbcr.win.width * 2))); + return ALIGN(len, 32); +} + +static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + isif_cfg.bayer.frm_fmt = frm_fmt; + else + isif_cfg.ycbcr.frm_fmt = frm_fmt; + return 0; +} +static enum ccdc_frmfmt isif_get_frame_format(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_cfg.bayer.frm_fmt; + return isif_cfg.ycbcr.frm_fmt; +} + +static int isif_getfid(void) +{ + return (regr(MODESET) >> 15) & 0x1; +} + +/* misc operations */ +static void isif_setfbaddr(unsigned long addr) +{ + regw((addr >> 21) & 0x07ff, CADU); + regw((addr >> 5) & 0x0ffff, CADL); +} + +static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) +{ + isif_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_BT656_10BIT: + case VPFE_YCBCR_SYNC_8: + isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_BT1120: + case VPFE_YCBCR_SYNC_16: + isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; + isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + case VPFE_RAW_BAYER: + isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + break; + default: + dev_dbg(isif_cfg.dev, "Invalid interface type\n"); + return -EINVAL; + } + + return 0; +} + +/* This function will configure ISIF for YCbCr parameters. */ +static int isif_config_ycbcr(void) +{ + struct isif_ycbcr_config *params = &isif_cfg.ycbcr; + struct vpss_pg_frame_size frame_size; + u32 modeset = 0, ccdcfg = 0; + struct vpss_sync_pol sync; + + dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); + + /* configure pixel format or input mode */ + modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | + (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | + (params->fid_pol << ISIF_FID_POL_SHIFT) | + (params->hd_pol << ISIF_HD_POL_SHIFT) | + (params->vd_pol << ISIF_VD_POL_SHIFT); + + /* pack the data to 8-bit ISIFCFG */ + switch (isif_cfg.if_type) { + case VPFE_BT656: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); + regw(3, REC656IF); + ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; + break; + case VPFE_BT656_10BIT: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + /* setup BT.656, embedded sync */ + regw(3, REC656IF); + /* enable 10 bit mode in ccdcfg */ + ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | + ISIF_BW656_ENABLE; + break; + case VPFE_BT1120: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + regw(3, REC656IF); + break; + + case VPFE_YCBCR_SYNC_8: + ccdcfg |= ISIF_DATA_PACK8; + ccdcfg |= ISIF_YCINSWP_YCBCR; + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + case VPFE_YCBCR_SYNC_16: + if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { + dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); + return -EINVAL; + } + break; + default: + /* should never come here */ + dev_dbg(isif_cfg.dev, "Invalid interface type\n"); + return -EINVAL; + } + + regw(modeset, MODESET); + + /* Set up pix order */ + ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; + + regw(ccdcfg, CCDCFG); + + /* configure video window */ + if ((isif_cfg.if_type == VPFE_BT1120) || + (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) + isif_setwin(¶ms->win, params->frm_fmt, 1); + else + isif_setwin(¶ms->win, params->frm_fmt, 2); + + /* + * 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->frm_fmt == CCDC_FRMFMT_INTERLACED) && + (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) + /* two fields are interleaved in memory */ + regw(0x00000249, SDOFST); + + /* Setup test pattern if enabled */ + if (isif_cfg.bayer.config_params.test_pat_gen) { + sync.ccdpg_hdpol = params->hd_pol; + sync.ccdpg_vdpol = params->vd_pol; + dm365_vpss_set_sync_pol(sync); + dm365_vpss_set_pg_frame_size(frame_size); + } + return 0; +} + +static int isif_configure(void) +{ + if (isif_cfg.if_type == VPFE_RAW_BAYER) + return isif_config_raw(); + return isif_config_ycbcr(); +} + +static int isif_close(struct device *device) +{ + /* copy defaults to module params */ + isif_cfg.bayer.config_params = isif_config_defaults; + return 0; +} + +static struct ccdc_hw_device isif_hw_dev = { + .name = "ISIF", + .owner = THIS_MODULE, + .hw_ops = { + .open = isif_open, + .close = isif_close, + .enable = isif_enable, + .enable_out_to_sdram = isif_enable_output_to_sdram, + .set_hw_if_params = isif_set_hw_if_params, + .configure = isif_configure, + .set_buftype = isif_set_buftype, + .get_buftype = isif_get_buftype, + .enum_pix = isif_enum_pix, + .set_pixel_format = isif_set_pixel_format, + .get_pixel_format = isif_get_pixel_format, + .set_frame_format = isif_set_frame_format, + .get_frame_format = isif_get_frame_format, + .set_image_window = isif_set_image_window, + .get_image_window = isif_get_image_window, + .get_line_length = isif_get_line_length, + .setfbaddr = isif_setfbaddr, + .getfid = isif_getfid, + }, +}; + +static int __init isif_probe(struct platform_device *pdev) +{ + void (*setup_pinmux)(void); + struct resource *res; + void *__iomem addr; + int status = 0, i; + + /* + * first try to register with vpfe. If not correct platform, then we + * don't have to iomap + */ + status = vpfe_register_ccdc_device(&isif_hw_dev); + if (status < 0) + return status; + + /* Get and enable Master clock */ + isif_cfg.mclk = clk_get(&pdev->dev, "master"); + if (IS_ERR(isif_cfg.mclk)) { + status = PTR_ERR(isif_cfg.mclk); + goto fail_mclk; + } + if (clk_enable(isif_cfg.mclk)) { + status = -ENODEV; + goto fail_mclk; + } + + /* Platform data holds setup_pinmux function ptr */ + if (NULL == pdev->dev.platform_data) { + status = -ENODEV; + goto fail_mclk; + } + setup_pinmux = pdev->dev.platform_data; + /* + * setup Mux configuration for ccdc which may be different for + * different SoCs using this CCDC + */ + setup_pinmux(); + + i = 0; + /* Get the ISIF base address, linearization table0 and table1 addr. */ + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) { + status = -ENODEV; + goto fail_nobase_res; + } + res = request_mem_region(res->start, resource_size(res), + res->name); + if (!res) { + status = -EBUSY; + goto fail_nobase_res; + } + addr = ioremap_nocache(res->start, resource_size(res)); + if (!addr) { + status = -ENOMEM; + goto fail_base_iomap; + } + switch (i) { + case 0: + /* ISIF base address */ + isif_cfg.base_addr = addr; + break; + case 1: + /* ISIF linear tbl0 address */ + isif_cfg.linear_tbl0_addr = addr; + break; + default: + /* ISIF linear tbl0 address */ + isif_cfg.linear_tbl1_addr = addr; + break; + } + i++; + } + isif_cfg.dev = &pdev->dev; + + printk(KERN_NOTICE "%s is registered with vpfe.\n", + isif_hw_dev.name); + return 0; +fail_base_iomap: + release_mem_region(res->start, resource_size(res)); + i--; +fail_nobase_res: + if (isif_cfg.base_addr) + iounmap(isif_cfg.base_addr); + if (isif_cfg.linear_tbl0_addr) + iounmap(isif_cfg.linear_tbl0_addr); + + while (i >= 0) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + release_mem_region(res->start, resource_size(res)); + i--; + } +fail_mclk: + clk_put(isif_cfg.mclk); + vpfe_unregister_ccdc_device(&isif_hw_dev); + return status; +} + +static int isif_remove(struct platform_device *pdev) +{ + struct resource *res; + int i = 0; + + iounmap(isif_cfg.base_addr); + iounmap(isif_cfg.linear_tbl0_addr); + iounmap(isif_cfg.linear_tbl1_addr); + while (i < 3) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (res) + release_mem_region(res->start, resource_size(res)); + i++; + } + vpfe_unregister_ccdc_device(&isif_hw_dev); + return 0; +} + +static struct platform_driver isif_driver = { + .driver = { + .name = "isif", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(isif_remove), + .probe = isif_probe, +}; + +static int __init isif_init(void) +{ + return platform_driver_register(&isif_driver); +} + +static void isif_exit(void) +{ + platform_driver_unregister(&isif_driver); +} + +module_init(isif_init); +module_exit(isif_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/ti-media/isif_regs.h b/drivers/media/video/ti-media/isif_regs.h new file mode 100644 index 0000000..aa69a46 --- /dev/null +++ b/drivers/media/video/ti-media/isif_regs.h @@ -0,0 +1,269 @@ +/* + * 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 _ISIF_REGS_H +#define _ISIF_REGS_H + +/* ISIF registers relative offsets */ +#define SYNCEN 0x00 +#define MODESET 0x04 +#define HDW 0x08 +#define VDW 0x0c +#define PPLN 0x10 +#define LPFR 0x14 +#define SPH 0x18 +#define LNH 0x1c +#define SLV0 0x20 +#define SLV1 0x24 +#define LNV 0x28 +#define CULH 0x2c +#define CULV 0x30 +#define HSIZE 0x34 +#define SDOFST 0x38 +#define CADU 0x3c +#define CADL 0x40 +#define LINCFG0 0x44 +#define LINCFG1 0x48 +#define CCOLP 0x4c +#define CRGAIN 0x50 +#define CGRGAIN 0x54 +#define CGBGAIN 0x58 +#define CBGAIN 0x5c +#define COFSTA 0x60 +#define FLSHCFG0 0x64 +#define FLSHCFG1 0x68 +#define FLSHCFG2 0x6c +#define VDINT0 0x70 +#define VDINT1 0x74 +#define VDINT2 0x78 +#define MISC 0x7c +#define CGAMMAWD 0x80 +#define REC656IF 0x84 +#define CCDCFG 0x88 +/***************************************************** +* Defect Correction registers +*****************************************************/ +#define DFCCTL 0x8c +#define VDFSATLV 0x90 +#define DFCMEMCTL 0x94 +#define DFCMEM0 0x98 +#define DFCMEM1 0x9c +#define DFCMEM2 0xa0 +#define DFCMEM3 0xa4 +#define DFCMEM4 0xa8 +/**************************************************** +* Black Clamp registers +****************************************************/ +#define CLAMPCFG 0xac +#define CLDCOFST 0xb0 +#define CLSV 0xb4 +#define CLHWIN0 0xb8 +#define CLHWIN1 0xbc +#define CLHWIN2 0xc0 +#define CLVRV 0xc4 +#define CLVWIN0 0xc8 +#define CLVWIN1 0xcc +#define CLVWIN2 0xd0 +#define CLVWIN3 0xd4 +/**************************************************** +* Lense Shading Correction +****************************************************/ +#define DATAHOFST 0xd8 +#define DATAVOFST 0xdc +#define LSCHVAL 0xe0 +#define LSCVVAL 0xe4 +#define TWODLSCCFG 0xe8 +#define TWODLSCOFST 0xec +#define TWODLSCINI 0xf0 +#define TWODLSCGRBU 0xf4 +#define TWODLSCGRBL 0xf8 +#define TWODLSCGROF 0xfc +#define TWODLSCORBU 0x100 +#define TWODLSCORBL 0x104 +#define TWODLSCOROF 0x108 +#define TWODLSCIRQEN 0x10c +#define TWODLSCIRQST 0x110 +/**************************************************** +* Data formatter +****************************************************/ +#define FMTCFG 0x114 +#define FMTPLEN 0x118 +#define FMTSPH 0x11c +#define FMTLNH 0x120 +#define FMTSLV 0x124 +#define FMTLNV 0x128 +#define FMTRLEN 0x12c +#define FMTHCNT 0x130 +#define FMTAPTR_BASE 0x134 +/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ +#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) +#define FMTPGMVF0 0x174 +#define FMTPGMVF1 0x178 +#define FMTPGMAPU0 0x17c +#define FMTPGMAPU1 0x180 +#define FMTPGMAPS0 0x184 +#define FMTPGMAPS1 0x188 +#define FMTPGMAPS2 0x18c +#define FMTPGMAPS3 0x190 +#define FMTPGMAPS4 0x194 +#define FMTPGMAPS5 0x198 +#define FMTPGMAPS6 0x19c +#define FMTPGMAPS7 0x1a0 +/************************************************ +* Color Space Converter +************************************************/ +#define CSCCTL 0x1a4 +#define CSCM0 0x1a8 +#define CSCM1 0x1ac +#define CSCM2 0x1b0 +#define CSCM3 0x1b4 +#define CSCM4 0x1b8 +#define CSCM5 0x1bc +#define CSCM6 0x1c0 +#define CSCM7 0x1c4 +#define OBWIN0 0x1c8 +#define OBWIN1 0x1cc +#define OBWIN2 0x1d0 +#define OBWIN3 0x1d4 +#define OBVAL0 0x1d8 +#define OBVAL1 0x1dc +#define OBVAL2 0x1e0 +#define OBVAL3 0x1e4 +#define OBVAL4 0x1e8 +#define OBVAL5 0x1ec +#define OBVAL6 0x1f0 +#define OBVAL7 0x1f4 +#define CLKCTL 0x1f8 + +/* Masks & Shifts below */ +#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 + +/* gain - offset masks */ +#define GAIN_INTEGER_SHIFT 9 +#define OFFSET_MASK 0xFFF +#define GAIN_SDRAM_EN_SHIFT 12 +#define GAIN_IPIPE_EN_SHIFT 13 +#define GAIN_H3A_EN_SHIFT 14 +#define OFST_SDRAM_EN_SHIFT 8 +#define OFST_IPIPE_EN_SHIFT 9 +#define OFST_H3A_EN_SHIFT 10 +#define GAIN_OFFSET_EN_MASK 0x7700 + +/* Culling */ +#define CULL_PAT_EVEN_LINE_SHIFT 8 + +/* CCDCFG register */ +#define ISIF_YCINSWP_RAW (0x00 << 4) +#define ISIF_YCINSWP_YCBCR (0x01 << 4) +#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) +#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) +#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) +#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) +#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) +#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) +#define ISIF_DATA_PACK_MASK 3 +#define ISIF_DATA_PACK16 0 +#define ISIF_DATA_PACK12 1 +#define ISIF_DATA_PACK8 2 +#define ISIF_PIX_ORDER_SHIFT 11 +#define ISIF_BW656_ENABLE (0x01 << 5) + +/* MODESET registers */ +#define ISIF_VDHDOUT_INPUT (0x00 << 0) +#define ISIF_INPUT_SHIFT 12 +#define ISIF_RAW_INPUT_MODE 0 +#define ISIF_FID_POL_SHIFT 4 +#define ISIF_HD_POL_SHIFT 3 +#define ISIF_VD_POL_SHIFT 2 +#define ISIF_DATAPOL_NORMAL 0 +#define ISIF_DATAPOL_SHIFT 6 +#define ISIF_EXWEN_DISABLE 0 +#define ISIF_EXWEN_SHIFT 5 +#define ISIF_FRM_FMT_SHIFT 7 +#define ISIF_DATASFT_SHIFT 8 +#define ISIF_LPF_SHIFT 14 +#define ISIF_LPF_MASK 1 + +/* GAMMAWD registers */ +#define ISIF_ALAW_GAMA_WD_MASK 0xF +#define ISIF_ALAW_GAMA_WD_SHIFT 1 +#define ISIF_ALAW_ENABLE 1 +#define ISIF_GAMMAWD_CFA_SHIFT 5 + +/* HSIZE registers */ +#define ISIF_HSIZE_FLIP_MASK 1 +#define ISIF_HSIZE_FLIP_SHIFT 12 + +/* MISC registers */ +#define ISIF_DPCM_EN_SHIFT 12 +#define ISIF_DPCM_PREDICTOR_SHIFT 13 + +/* Black clamp related */ +#define ISIF_BC_MODE_COLOR_SHIFT 4 +#define ISIF_HORZ_BC_MODE_SHIFT 1 +#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 +#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 +#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 +#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 +#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 +#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 + +/* VDFC registers */ +#define ISIF_VDFC_EN_SHIFT 4 +#define ISIF_VDFC_CORR_MOD_SHIFT 5 +#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 +#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 +#define ISIF_VDFC_POS_MASK 0x1FFF +#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 + +/* CSC registers */ +#define ISIF_CSC_COEF_INTEG_MASK 7 +#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f +#define ISIF_CSC_COEF_INTEG_SHIFT 5 +#define ISIF_CSCM_MSB_SHIFT 8 +#define ISIF_DF_CSC_SPH_MASK 0x1FFF +#define ISIF_DF_CSC_LNH_MASK 0x1FFF +#define ISIF_DF_CSC_SLV_MASK 0x1FFF +#define ISIF_DF_CSC_LNV_MASK 0x1FFF +#define ISIF_DF_NUMLINES 0x7FFF +#define ISIF_DF_NUMPIX 0x1FFF + +/* Offsets for LSC/DFC/Gain */ +#define ISIF_DATA_H_OFFSET_MASK 0x1FFF +#define ISIF_DATA_V_OFFSET_MASK 0x1FFF + +/* Linearization */ +#define ISIF_LIN_CORRSFT_SHIFT 4 +#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 + + +/* Pattern registers */ +#define ISIF_PG_EN (1 << 3) +#define ISIF_SEL_PG_SRC (3 << 4) +#define ISIF_PG_VD_POL_SHIFT 0 +#define ISIF_PG_HD_POL_SHIFT 1 + +/*random other junk*/ +#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) +#define ISIF_SYNCEN_WEN_MASK (1 << 1) +#define ISIF_SYNCEN_WEN_SHIFT 1 + +#endif diff --git a/drivers/media/video/ti-media/vpfe_capture.c b/drivers/media/video/ti-media/vpfe_capture.c new file mode 100644 index 0000000..2585cc3 --- /dev/null +++ b/drivers/media/video/ti-media/vpfe_capture.c @@ -0,0 +1,2080 @@ +/* + * 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 + * + * Driver name : VPFE Capture driver + * VPFE Capture driver allows applications to capture and stream video + * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as + * TVP5146 or Raw Bayer RGB image data from an image sensor + * such as Microns' MT9T001, MT9T031 etc. + * + * These SoCs have, in common, a Video Processing Subsystem (VPSS) that + * consists of a Video Processing Front End (VPFE) for capturing + * video/raw image data and Video Processing Back End (VPBE) for displaying + * YUV data through an in-built analog encoder or Digital LCD port. This + * driver is for capture through VPFE. A typical EVM using these SoCs have + * following high level configuration. + * + * + * decoder(TVP5146/ YUV/ + * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) + * data input | | + * V | + * SDRAM | + * V + * Image Processor + * | + * V + * SDRAM + * The data flow happens from a decoder connected to the VPFE over a + * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface + * and to the input of VPFE through an optional MUX (if more inputs are + * to be interfaced on the EVM). The input data is first passed through + * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC + * does very little or no processing on YUV data and does pre-process Raw + * Bayer RGB data through modules such as Defect Pixel Correction (DFC) + * Color Space Conversion (CSC), data gain/offset etc. After this, data + * can be written to SDRAM or can be connected to the image processing + * block such as IPIPE (on DM355 only). + * + * Features supported + * - MMAP IO + * - Capture using TVP5146 over BT.656 + * - support for interfacing decoders using sub device model + * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV + * data capture to SDRAM. + * TODO list + * - Support multiple REQBUF after open + * - Support for de-allocating buffers through REQBUF + * - Support for Raw Bayer RGB capture + * - Support for chaining Image Processor + * - Support for static allocation of buffers + * - Support for USERPTR IO + * - Support for STREAMON before QBUF + * - Support for control ioctls + */ +#include +#include +#include +#include +#include +#include +#include +#include "ccdc_hw_device.h" + +static int debug; +static u32 numbuffers = 3; +static u32 bufsize = (720 * 576 * 2); + +module_param(numbuffers, uint, S_IRUGO); +module_param(bufsize, uint, S_IRUGO); +module_param(debug, int, 0644); + +MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); +MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Texas Instruments"); + +/* standard information */ +struct vpfe_standard { + v4l2_std_id std_id; + unsigned int width; + unsigned int height; + struct v4l2_fract pixelaspect; + /* 0 - progressive, 1 - interlaced */ + int frame_format; +}; + +/* ccdc configuration */ +struct ccdc_config { + /* This make sure vpfe is probed and ready to go */ + int vpfe_probed; + /* name of ccdc device */ + char name[32]; +}; + +/* data structures */ +static struct vpfe_config_params config_params = { + .min_numbuffers = 3, + .numbuffers = 3, + .min_bufsize = 720 * 480 * 2, + .device_bufsize = 720 * 576 * 2, +}; + +/* ccdc device registered */ +static struct ccdc_hw_device *ccdc_dev; +/* lock for accessing ccdc information */ +static DEFINE_MUTEX(ccdc_lock); +/* ccdc configuration */ +static struct ccdc_config *ccdc_cfg; + +const struct vpfe_standard vpfe_standards[] = { + {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, + {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, +}; + +/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ +static const struct vpfe_pixel_format vpfe_pix_fmts[] = { + { + .fmtdesc = { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer GrRBGb 8bit A-Law compr.", + .pixelformat = V4L2_PIX_FMT_SBGGR8, + }, + .bpp = 1, + }, + { + .fmtdesc = { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer GrRBGb - 16bit", + .pixelformat = V4L2_PIX_FMT_SBGGR16, + }, + .bpp = 2, + }, + { + .fmtdesc = { + .index = 2, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Bayer GrRBGb 8bit DPCM compr.", + .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, + }, + .bpp = 1, + }, + { + .fmtdesc = { + .index = 3, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "YCbCr 4:2:2 Interleaved UYVY", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, + .bpp = 2, + }, + { + .fmtdesc = { + .index = 4, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "YCbCr 4:2:2 Interleaved YUYV", + .pixelformat = V4L2_PIX_FMT_YUYV, + }, + .bpp = 2, + }, + { + .fmtdesc = { + .index = 5, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .description = "Y/CbCr 4:2:0 - Semi planar", + .pixelformat = V4L2_PIX_FMT_NV12, + }, + .bpp = 1, + }, +}; + +/* + * vpfe_lookup_pix_format() + * lookup an entry in the vpfe pix format table based on pix_format + */ +static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { + if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) + return &vpfe_pix_fmts[i]; + } + return NULL; +} + +/* + * vpfe_register_ccdc_device. CCDC module calls this to + * register with vpfe capture + */ +int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) +{ + int ret = 0; + printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); + + BUG_ON(!dev->hw_ops.open); + BUG_ON(!dev->hw_ops.enable); + BUG_ON(!dev->hw_ops.set_hw_if_params); + BUG_ON(!dev->hw_ops.configure); + BUG_ON(!dev->hw_ops.set_buftype); + BUG_ON(!dev->hw_ops.get_buftype); + BUG_ON(!dev->hw_ops.enum_pix); + BUG_ON(!dev->hw_ops.set_frame_format); + BUG_ON(!dev->hw_ops.get_frame_format); + BUG_ON(!dev->hw_ops.get_pixel_format); + BUG_ON(!dev->hw_ops.set_pixel_format); + BUG_ON(!dev->hw_ops.set_params); + BUG_ON(!dev->hw_ops.set_image_window); + BUG_ON(!dev->hw_ops.get_image_window); + BUG_ON(!dev->hw_ops.get_line_length); + BUG_ON(!dev->hw_ops.getfid); + + mutex_lock(&ccdc_lock); + if (NULL == ccdc_cfg) { + /* + * TODO. Will this ever happen? if so, we need to fix it. + * Proabably we need to add the request to a linked list and + * walk through it during vpfe probe + */ + printk(KERN_ERR "vpfe capture not initialized\n"); + ret = -EFAULT; + goto unlock; + } + + if (strcmp(dev->name, ccdc_cfg->name)) { + /* ignore this ccdc */ + ret = -EINVAL; + goto unlock; + } + + if (ccdc_dev) { + printk(KERN_ERR "ccdc already registered\n"); + ret = -EINVAL; + goto unlock; + } + + ccdc_dev = dev; +unlock: + mutex_unlock(&ccdc_lock); + return ret; +} +EXPORT_SYMBOL(vpfe_register_ccdc_device); + +/* + * vpfe_unregister_ccdc_device. CCDC module calls this to + * unregister with vpfe capture + */ +void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) +{ + if (NULL == dev) { + printk(KERN_ERR "invalid ccdc device ptr\n"); + return; + } + + printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", + dev->name); + + if (strcmp(dev->name, ccdc_cfg->name)) { + /* ignore this ccdc */ + return; + } + + mutex_lock(&ccdc_lock); + ccdc_dev = NULL; + mutex_unlock(&ccdc_lock); + return; +} +EXPORT_SYMBOL(vpfe_unregister_ccdc_device); + +/* + * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings + */ +static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, + struct v4l2_format *f) +{ + struct v4l2_rect image_win; + enum ccdc_buftype buf_type; + enum ccdc_frmfmt frm_fmt; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ccdc_dev->hw_ops.get_image_window(&image_win); + f->fmt.pix.width = image_win.width; + f->fmt.pix.height = image_win.height; + f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; + buf_type = ccdc_dev->hw_ops.get_buftype(); + f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format(); + frm_fmt = ccdc_dev->hw_ops.get_frame_format(); + 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 { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n"); + return -EINVAL; + } + } else { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n"); + return -EINVAL; + } + return 0; +} + +/* + * vpfe_config_ccdc_image_format() + * For a pix format, configure ccdc to setup the capture + */ +static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) +{ + enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; + int ret = 0; + + if (ccdc_dev->hw_ops.set_pixel_format( + vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "couldn't set pix format in ccdc\n"); + return -EINVAL; + } + /* configure the image window */ + ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); + + switch (vpfe_dev->fmt.fmt.pix.field) { + case V4L2_FIELD_INTERLACED: + /* do nothing, since it is default */ + ret = ccdc_dev->hw_ops.set_buftype( + CCDC_BUFTYPE_FLD_INTERLEAVED); + break; + case V4L2_FIELD_NONE: + frm_fmt = CCDC_FRMFMT_PROGRESSIVE; + /* buffer type only applicable for interlaced scan */ + break; + case V4L2_FIELD_SEQ_TB: + ret = ccdc_dev->hw_ops.set_buftype( + CCDC_BUFTYPE_FLD_SEPARATED); + break; + default: + return -EINVAL; + } + + /* set the frame format */ + if (!ret) + ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); + return ret; +} +/* + * vpfe_config_image_format() + * For a given standard, this functions sets up the default + * pix format & crop values in the vpfe device and ccdc. It first + * starts with defaults based values from the standard table. + * It then checks if sub device support g_fmt and then override the + * values based on that.Sets crop values to match with scan resolution + * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the + * values in ccdc + */ +static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, + const v4l2_std_id *std_id) +{ + struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { + if (vpfe_standards[i].std_id & *std_id) { + vpfe_dev->std_info.active_pixels = + vpfe_standards[i].width; + vpfe_dev->std_info.active_lines = + vpfe_standards[i].height; + vpfe_dev->std_info.frame_format = + vpfe_standards[i].frame_format; + vpfe_dev->std_index = i; + break; + } + } + + if (i == ARRAY_SIZE(vpfe_standards)) { + v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); + return -EINVAL; + } + + vpfe_dev->crop.top = 0; + vpfe_dev->crop.left = 0; + vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; + vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; + vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width; + vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height; + + /* first field and frame format based on standard frame format */ + if (vpfe_dev->std_info.frame_format) { + vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + /* assume V4L2_PIX_FMT_UYVY as default */ + vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + } else { + vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE; + /* assume V4L2_PIX_FMT_SBGGR8 */ + vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; + } + + /* if sub device supports g_fmt, override the defaults */ + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt); + + if (ret && ret != -ENOIOCTLCMD) { + v4l2_err(&vpfe_dev->v4l2_dev, + "error in getting g_fmt from sub device\n"); + return ret; + } + + /* Sets the values in CCDC */ + ret = vpfe_config_ccdc_image_format(vpfe_dev); + if (ret) + return ret; + + /* Update the values of sizeimage and bytesperline */ + if (!ret) { + vpfe_dev->fmt.fmt.pix.bytesperline = + ccdc_dev->hw_ops.get_line_length(); + vpfe_dev->fmt.fmt.pix.sizeimage = + vpfe_dev->fmt.fmt.pix.bytesperline * + vpfe_dev->fmt.fmt.pix.height; + } + return ret; +} + +static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) +{ + int ret = 0; + + /* set first input of current subdevice as the current input */ + vpfe_dev->current_input = 0; + + /* set default standard */ + vpfe_dev->std_index = 0; + + /* Configure the default format information */ + ret = vpfe_config_image_format(vpfe_dev, + &vpfe_standards[vpfe_dev->std_index].std_id); + if (ret) + return ret; + + /* now open the ccdc device to initialize it */ + mutex_lock(&ccdc_lock); + if (NULL == ccdc_dev) { + v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); + ret = -ENODEV; + goto unlock; + } + + if (!try_module_get(ccdc_dev->owner)) { + v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); + ret = -ENODEV; + goto unlock; + } + ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); + if (!ret) + vpfe_dev->initialized = 1; + + /* Clear all VPFE/CCDC interrupts */ + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(-1); + +unlock: + mutex_unlock(&ccdc_lock); + return ret; +} + +/* + * vpfe_open : It creates object of file handle structure and + * stores it in private_data member of filepointer + */ +static int vpfe_open(struct file *file) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); + + if (!vpfe_dev->cfg->num_subdevs) { + v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); + return -ENODEV; + } + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); + if (NULL == fh) { + v4l2_err(&vpfe_dev->v4l2_dev, + "unable to allocate memory for file handle object\n"); + return -ENOMEM; + } + /* store pointer to fh in private_data member of file */ + file->private_data = fh; + fh->vpfe_dev = vpfe_dev; + mutex_lock(&vpfe_dev->lock); + /* If decoder is not initialized. initialize it */ + if (!vpfe_dev->initialized) { + if (vpfe_initialize_device(vpfe_dev)) { + mutex_unlock(&vpfe_dev->lock); + return -ENODEV; + } + } + /* Increment device usrs counter */ + vpfe_dev->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&vpfe_dev->prio, &fh->prio); + mutex_unlock(&vpfe_dev->lock); + return 0; +} + +static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) +{ + unsigned long addr; + + vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, + struct videobuf_buffer, queue); + list_del(&vpfe_dev->next_frm->queue); + vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; + addr = videobuf_to_dma_contig(vpfe_dev->next_frm); + + ccdc_dev->hw_ops.setfbaddr(addr); +} + +static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) +{ + unsigned long addr; + + addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); + addr += vpfe_dev->field_off; + ccdc_dev->hw_ops.setfbaddr(addr); +} + +static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) +{ + struct timeval timevalue; + + do_gettimeofday(&timevalue); + vpfe_dev->cur_frm->ts = timevalue; + vpfe_dev->cur_frm->state = VIDEOBUF_DONE; + vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; + wake_up_interruptible(&vpfe_dev->cur_frm->done); + vpfe_dev->cur_frm = vpfe_dev->next_frm; +} + +/* ISR for VINT0*/ +static irqreturn_t vpfe_isr(int irq, void *dev_id) +{ + struct vpfe_device *vpfe_dev = dev_id; + enum v4l2_field field; + int fid; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); + field = vpfe_dev->fmt.fmt.pix.field; + + /* if streaming not started, don't do anything */ + if (!vpfe_dev->started) + goto clear_intr; + + /* only for 6446 this will be applicable */ + if (NULL != ccdc_dev->hw_ops.reset) + ccdc_dev->hw_ops.reset(); + + if (field == V4L2_FIELD_NONE) { + /* handle progressive frame capture */ + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "frame format is progressive...\n"); + if (vpfe_dev->cur_frm != vpfe_dev->next_frm) + vpfe_process_buffer_complete(vpfe_dev); + goto clear_intr; + } + + /* interlaced or TB capture check which field we are in hardware */ + fid = ccdc_dev->hw_ops.getfid(); + + /* switch the software maintained field id */ + vpfe_dev->field_id ^= 1; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", + fid, vpfe_dev->field_id); + if (fid == vpfe_dev->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_dev->cur_frm != vpfe_dev->next_frm) + vpfe_process_buffer_complete(vpfe_dev); + /* + * based on whether the two fields are stored + * interleavely or separately in memory, reconfigure + * the CCDC memory address + */ + if (field == V4L2_FIELD_SEQ_TB) + vpfe_schedule_bottom_field(vpfe_dev); + + goto clear_intr; + } + /* + * 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 + */ + spin_lock(&vpfe_dev->dma_queue_lock); + if (!list_empty(&vpfe_dev->dma_queue) && + vpfe_dev->cur_frm == vpfe_dev->next_frm) + vpfe_schedule_next_buffer(vpfe_dev); + spin_unlock(&vpfe_dev->dma_queue_lock); + } else if (fid == 0) { + /* + * out of sync. Recover from any hardware out-of-sync. + * May loose one frame + */ + vpfe_dev->field_id = fid; + } +clear_intr: + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(irq); + + return IRQ_HANDLED; +} + +/* vdint1_isr - isr handler for VINT1 interrupt */ +static irqreturn_t vdint1_isr(int irq, void *dev_id) +{ + struct vpfe_device *vpfe_dev = dev_id; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); + + /* if streaming not started, don't do anything */ + if (!vpfe_dev->started) { + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(irq); + return IRQ_HANDLED; + } + + spin_lock(&vpfe_dev->dma_queue_lock); + if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && + !list_empty(&vpfe_dev->dma_queue) && + vpfe_dev->cur_frm == vpfe_dev->next_frm) + vpfe_schedule_next_buffer(vpfe_dev); + spin_unlock(&vpfe_dev->dma_queue_lock); + + if (vpfe_dev->cfg->clr_intr) + vpfe_dev->cfg->clr_intr(irq); + + return IRQ_HANDLED; +} + +static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) +{ + enum ccdc_frmfmt frame_format; + + frame_format = ccdc_dev->hw_ops.get_frame_format(); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) + free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); +} + +static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) +{ + enum ccdc_frmfmt frame_format; + + frame_format = ccdc_dev->hw_ops.get_frame_format(); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { + return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, + IRQF_DISABLED, "vpfe_capture1", + vpfe_dev); + } + return 0; +} + +/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ +static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) +{ + vpfe_dev->started = 0; + ccdc_dev->hw_ops.enable(0); + if (ccdc_dev->hw_ops.enable_out_to_sdram) + ccdc_dev->hw_ops.enable_out_to_sdram(0); +} + +/* + * vpfe_release : This function deletes buffer queue, frees the + * buffers and the vpfe file handle + */ +static int vpfe_release(struct file *file) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + struct vpfe_subdev_info *sdinfo; + int ret; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); + + /* Get the device lock */ + mutex_lock(&vpfe_dev->lock); + /* if this instance is doing IO */ + if (fh->io_allowed) { + if (vpfe_dev->started) { + sdinfo = vpfe_dev->current_subdev; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, + sdinfo->grp_id, + video, s_stream, 0); + if (ret && (ret != -ENOIOCTLCMD)) + v4l2_err(&vpfe_dev->v4l2_dev, + "stream off failed in subdev\n"); + vpfe_stop_ccdc_capture(vpfe_dev); + vpfe_detach_irq(vpfe_dev); + videobuf_streamoff(&vpfe_dev->buffer_queue); + } + vpfe_dev->io_usrs = 0; + vpfe_dev->numbuffers = config_params.numbuffers; + } + + /* Decrement device usrs counter */ + vpfe_dev->usrs--; + /* Close the priority */ + v4l2_prio_close(&vpfe_dev->prio, &fh->prio); + /* If this is the last file handle */ + if (!vpfe_dev->usrs) { + vpfe_dev->initialized = 0; + if (ccdc_dev->hw_ops.close) + ccdc_dev->hw_ops.close(vpfe_dev->pdev); + module_put(ccdc_dev->owner); + } + mutex_unlock(&vpfe_dev->lock); + file->private_data = NULL; + /* Free memory allocated to file handle object */ + kfree(fh); + return 0; +} + +/* + * vpfe_mmap : It is used to map kernel space buffers + * into user spaces + */ +static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* Get the device object and file handle object */ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); + + return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); +} + +/* + * vpfe_poll: It is used for select/poll system call + */ +static unsigned int vpfe_poll(struct file *file, poll_table *wait) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); + + if (vpfe_dev->started) + return videobuf_poll_stream(file, + &vpfe_dev->buffer_queue, wait); + return 0; +} + +/* vpfe capture driver file operations */ +static const struct v4l2_file_operations vpfe_fops = { + .owner = THIS_MODULE, + .open = vpfe_open, + .release = vpfe_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vpfe_mmap, + .poll = vpfe_poll +}; + +/* + * vpfe_check_format() + * This function adjust the input pixel format as per hardware + * capabilities and update the same in pixfmt. + * Following algorithm used :- + * + * If given pixformat is not in the vpfe list of pix formats or not + * supported by the hardware, current value of pixformat in the device + * is used + * If given field is not supported, then current field is used. If field + * is different from current, then it is matched with that from sub device. + * Minimum height is 2 lines for interlaced or tb field and 1 line for + * progressive. Maximum height is clamped to active active lines of scan + * Minimum width is 32 bytes in memory and width is clamped to active + * pixels of scan. + * bytesperline is a multiple of 32. + */ +static const struct vpfe_pixel_format * + vpfe_check_format(struct vpfe_device *vpfe_dev, + struct v4l2_pix_format *pixfmt) +{ + u32 min_height = 1, min_width = 32, max_width, max_height; + const struct vpfe_pixel_format *vpfe_pix_fmt; + u32 pix; + int temp, found; + + vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); + if (NULL == vpfe_pix_fmt) { + /* + * use current pixel format in the vpfe device. We + * will find this pix format in the table + */ + pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; + vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); + } + + /* check if hw supports it */ + temp = 0; + found = 0; + while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { + if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { + found = 1; + break; + } + temp++; + } + + if (!found) { + /* use current pixel format */ + pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; + /* + * Since this is currently used in the vpfe device, we + * will find this pix format in the table + */ + vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); + } + + /* check what field format is supported */ + if (pixfmt->field == V4L2_FIELD_ANY) { + /* if field is any, use current value as default */ + pixfmt->field = vpfe_dev->fmt.fmt.pix.field; + } + + /* + * if field is not same as current field in the vpfe device + * try matching the field with the sub device field + */ + if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { + /* + * If field value is not in the supported fields, use current + * field used in the device as default + */ + switch (pixfmt->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + /* if sub device is supporting progressive, use that */ + if (!vpfe_dev->std_info.frame_format) + pixfmt->field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_NONE: + if (vpfe_dev->std_info.frame_format) + pixfmt->field = V4L2_FIELD_INTERLACED; + break; + + default: + /* use current field as default */ + pixfmt->field = vpfe_dev->fmt.fmt.pix.field; + break; + } + } + + /* Now adjust image resolutions supported */ + if (pixfmt->field == V4L2_FIELD_INTERLACED || + pixfmt->field == V4L2_FIELD_SEQ_TB) + min_height = 2; + + max_width = vpfe_dev->std_info.active_pixels; + max_height = vpfe_dev->std_info.active_lines; + min_width /= vpfe_pix_fmt->bpp; + + v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", + pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); + + pixfmt->width = clamp((pixfmt->width), min_width, max_width); + pixfmt->height = clamp((pixfmt->height), min_height, max_height); + + /* If interlaced, adjust height to be a multiple of 2 */ + if (pixfmt->field == V4L2_FIELD_INTERLACED) + pixfmt->height &= (~1); + /* + * recalculate bytesperline and sizeimage since width + * and height might have changed + */ + pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) + & ~31); + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) + pixfmt->sizeimage = + pixfmt->bytesperline * pixfmt->height + + ((pixfmt->bytesperline * pixfmt->height) >> 1); + else + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + + v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" + " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", + pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, + pixfmt->bytesperline, pixfmt->sizeimage); + return vpfe_pix_fmt; +} + +static int vpfe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); + + cap->version = VPFE_CAPTURE_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); + strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); + return 0; +} + +static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); + /* Fill in the information about format */ + *fmt = vpfe_dev->fmt; + return ret; +} + +static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + const struct vpfe_pixel_format *pix_fmt; + int temp_index; + u32 pix; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); + + if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) + return -EINVAL; + + /* Fill in the information about format */ + pix_fmt = vpfe_lookup_pix_format(pix); + if (NULL != pix_fmt) { + temp_index = fmt->index; + *fmt = pix_fmt->fmtdesc; + fmt->index = temp_index; + return 0; + } + return -EINVAL; +} + +static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + const struct vpfe_pixel_format *pix_fmts; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); + + /* If streaming is started, return error */ + if (vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); + return -EBUSY; + } + + /* Check for valid frame format */ + pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); + + if (NULL == pix_fmts) + return -EINVAL; + + /* store the pixel format in the device object */ + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + /* First detach any IRQ if currently attached */ + vpfe_detach_irq(vpfe_dev); + vpfe_dev->fmt = *fmt; + /* set image capture parameters in the ccdc */ + ret = vpfe_config_ccdc_image_format(vpfe_dev); + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + const struct vpfe_pixel_format *pix_fmts; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); + + pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); + if (NULL == pix_fmts) + return -EINVAL; + return 0; +} + +/* + * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a + * given app input index + */ +static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, + int *subdev_index, + int *subdev_input_index, + int app_input_index) +{ + struct vpfe_config *cfg = vpfe_dev->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < cfg->num_subdevs; i++) { + sdinfo = &cfg->sub_devs[i]; + if (app_input_index < (j + sdinfo->num_inputs)) { + *subdev_index = i; + *subdev_input_index = app_input_index - j; + return 0; + } + j += sdinfo->num_inputs; + } + return -EINVAL; +} + +/* + * vpfe_get_app_input - Get app input index for a given subdev input index + * driver stores the input index of the current sub device and translate it + * when application request the current input + */ +static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, + int *app_input_index) +{ + struct vpfe_config *cfg = vpfe_dev->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < cfg->num_subdevs; i++) { + sdinfo = &cfg->sub_devs[i]; + if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { + if (vpfe_dev->current_input >= sdinfo->num_inputs) + return -1; + *app_input_index = j + vpfe_dev->current_input; + return 0; + } + j += sdinfo->num_inputs; + } + return -EINVAL; +} + +static int vpfe_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int subdev, index ; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); + + if (vpfe_get_subdev_input_index(vpfe_dev, + &subdev, + &index, + inp->index) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" + " for the subdev\n"); + return -EINVAL; + } + sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; + memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); + return 0; +} + +static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); + + return vpfe_get_app_input_index(vpfe_dev, index); +} + + +static int vpfe_s_input(struct file *file, void *priv, unsigned int index) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int subdev_index, inp_index; + struct vpfe_route *route; + u32 input = 0, output = 0; + int ret = -EINVAL; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + /* + * If streaming is started return device busy + * error + */ + if (vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); + ret = -EBUSY; + goto unlock_out; + } + + if (vpfe_get_subdev_input_index(vpfe_dev, + &subdev_index, + &inp_index, + index) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); + goto unlock_out; + } + + sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; + route = &sdinfo->routes[inp_index]; + if (route && sdinfo->can_route) { + input = route->input; + output = route->output; + } + + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, s_routing, input, output, 0); + + if (ret) { + v4l2_err(&vpfe_dev->v4l2_dev, + "vpfe_doioctl:error in setting input in decoder\n"); + ret = -EINVAL; + goto unlock_out; + } + vpfe_dev->current_subdev = sdinfo; + vpfe_dev->current_input = index; + vpfe_dev->std_index = 0; + + /* set the bus/interface parameter for the sub device in ccdc */ + ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); + if (ret) + goto unlock_out; + + /* set the default image parameters in the device */ + ret = vpfe_config_image_format(vpfe_dev, + &vpfe_standards[vpfe_dev->std_index].std_id); +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + sdinfo = vpfe_dev->current_subdev; + if (ret) + return ret; + /* Call querystd function of decoder device */ + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, querystd, std_id); + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); + + /* Call decoder driver function to set the standard */ + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + sdinfo = vpfe_dev->current_subdev; + /* If streaming is started, return device busy error */ + if (vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); + ret = -EBUSY; + goto unlock_out; + } + + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, s_std, *std_id); + if (ret < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); + goto unlock_out; + } + ret = vpfe_config_image_format(vpfe_dev, std_id); + +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); + + *std_id = vpfe_standards[vpfe_dev->std_index].std_id; + return 0; +} +/* + * Videobuf operations + */ +static int vpfe_videobuf_setup(struct videobuf_queue *vq, + unsigned int *count, + unsigned int *size) +{ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); + *size = vpfe_dev->fmt.fmt.pix.sizeimage; + if (vpfe_dev->memory == V4L2_MEMORY_MMAP && + vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) + *size = config_params.device_bufsize; + + if (*count < config_params.min_numbuffers) + *count = config_params.min_numbuffers; + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "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) +{ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + unsigned long addr; + int ret; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); + + /* If buffer is not initialized, initialize it */ + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = vpfe_dev->fmt.fmt.pix.width; + vb->height = vpfe_dev->fmt.fmt.pix.height; + vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; + vb->field = field; + + ret = videobuf_iolock(vq, vb, NULL);; + if (ret < 0) + return ret; + + addr = videobuf_to_dma_contig(vb); + /* Make sure user addresses are aligned to 32 bytes */ + if (!ALIGN(addr, 32)) + return -EINVAL; + + vb->state = VIDEOBUF_PREPARED; + } + return 0; +} + +static void vpfe_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and device object */ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); + list_add_tail(&vb->queue, &vpfe_dev->dma_queue); + spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); + + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +static void vpfe_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct vpfe_fh *fh = vq->priv_data; + struct vpfe_device *vpfe_dev = fh->vpfe_dev; + unsigned long flags; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); + + /* + * We need to flush the buffer from the dma queue since + * they are de-allocated + */ + spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); + INIT_LIST_HEAD(&vpfe_dev->dma_queue); + spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); + 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, +}; + +/* + * vpfe_reqbufs. currently support REQBUF only once opening + * the device. + */ +static int vpfe_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req_buf) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + if (vpfe_dev->io_usrs != 0) { + v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); + ret = -EBUSY; + goto unlock_out; + } + + vpfe_dev->memory = req_buf->memory; + videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, + &vpfe_videobuf_qops, + vpfe_dev->pdev, + &vpfe_dev->irqlock, + req_buf->type, + vpfe_dev->fmt.fmt.pix.field, + sizeof(struct videobuf_buffer), + fh); + + fh->io_allowed = 1; + vpfe_dev->io_usrs = 1; + INIT_LIST_HEAD(&vpfe_dev->dma_queue); + ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); + return -EINVAL; + } + /* Call videobuf_querybuf to get information */ + return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); +} + +static int vpfe_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + /* + * If this file handle is not allowed to do IO, + * return error + */ + if (!fh->io_allowed) { + v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); + return -EACCES; + } + return videobuf_qbuf(&vpfe_dev->buffer_queue, p); +} + +static int vpfe_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + return videobuf_dqbuf(&vpfe_dev->buffer_queue, + buf, file->f_flags & O_NONBLOCK); +} + +static int vpfe_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + sdinfo = vpfe_dev->current_subdev; + + return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, queryctrl, qctrl); + +} + +static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + sdinfo = vpfe_dev->current_subdev; + + return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, g_ctrl, ctrl); +} + +static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + sdinfo = vpfe_dev->current_subdev; + + return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + core, s_ctrl, ctrl); +} + +/* + * vpfe_calculate_offsets : This function calculates buffers offset + * for top and bottom field + */ +static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) +{ + struct v4l2_rect image_win; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); + + ccdc_dev->hw_ops.get_image_window(&image_win); + vpfe_dev->field_off = image_win.height * image_win.width; +} + +/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ +static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) +{ + ccdc_dev->hw_ops.enable(1); + if (ccdc_dev->hw_ops.enable_out_to_sdram) + ccdc_dev->hw_ops.enable_out_to_sdram(1); + vpfe_dev->started = 1; +} + +/* + * vpfe_streamon. Assume the DMA queue is not empty. + * application is expected to call QBUF before calling + * this ioctl. If not, driver returns error + */ +static int vpfe_streamon(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + struct vpfe_subdev_info *sdinfo; + unsigned long addr; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); + return -EACCES; + } + + sdinfo = vpfe_dev->current_subdev; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, s_stream, 1); + + if (ret && (ret != -ENOIOCTLCMD)) { + v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); + return -EINVAL; + } + + /* If buffer queue is empty, return error */ + if (list_empty(&vpfe_dev->buffer_queue.stream)) { + v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); + return -EIO; + } + + /* Call videobuf_streamon to start streaming * in videobuf */ + ret = videobuf_streamon(&vpfe_dev->buffer_queue); + if (ret) + return ret; + + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + goto streamoff; + /* Get the next frame from the buffer queue */ + vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, + struct videobuf_buffer, queue); + vpfe_dev->cur_frm = vpfe_dev->next_frm; + /* Remove buffer from the buffer queue */ + list_del(&vpfe_dev->cur_frm->queue); + /* Mark state of the current frame to active */ + vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + vpfe_dev->field_id = 0; + addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); + + /* Calculate field offset */ + vpfe_calculate_offsets(vpfe_dev); + + if (vpfe_attach_irq(vpfe_dev) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Error in attaching interrupt handle\n"); + ret = -EFAULT; + goto unlock_out; + } + if (ccdc_dev->hw_ops.configure() < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Error in configuring ccdc\n"); + ret = -EINVAL; + goto unlock_out; + } + ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); + vpfe_start_ccdc_capture(vpfe_dev); + mutex_unlock(&vpfe_dev->lock); + return ret; +unlock_out: + mutex_unlock(&vpfe_dev->lock); +streamoff: + ret = videobuf_streamoff(&vpfe_dev->buffer_queue); + return ret; +} + +static int vpfe_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buf_type) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + struct vpfe_fh *fh = file->private_data; + struct vpfe_subdev_info *sdinfo; + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { + v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed) { + v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!vpfe_dev->started) { + v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + vpfe_stop_ccdc_capture(vpfe_dev); + vpfe_detach_irq(vpfe_dev); + + sdinfo = vpfe_dev->current_subdev; + ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, + video, s_stream, 0); + + if (ret && (ret != -ENOIOCTLCMD)) + v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); + ret = videobuf_streamoff(&vpfe_dev->buffer_queue); + mutex_unlock(&vpfe_dev->lock); + return ret; +} + +static int vpfe_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); + + if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_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[vpfe_dev->std_index].width; + crop->bounds.height = crop->defrect.height = + vpfe_standards[vpfe_dev->std_index].height; + crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; + return 0; +} + +static int vpfe_g_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); + + crop->c = vpfe_dev->crop; + return 0; +} + +static int vpfe_s_crop(struct file *file, void *priv, + struct v4l2_crop *crop) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); + + if (vpfe_dev->started) { + /* make sure streaming is not started */ + v4l2_err(&vpfe_dev->v4l2_dev, + "Cannot change crop when streaming is ON\n"); + return -EBUSY; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + if (crop->c.top < 0 || crop->c.left < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "doesn't support negative values for top & left\n"); + ret = -EINVAL; + goto unlock_out; + } + + /* adjust the width to 16 pixel boundry */ + crop->c.width = ((crop->c.width + 15) & ~0xf); + + /* make sure parameters are valid */ + if ((crop->c.left + crop->c.width > + vpfe_dev->std_info.active_pixels) || + (crop->c.top + crop->c.height > + vpfe_dev->std_info.active_lines)) { + v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); + ret = -EINVAL; + goto unlock_out; + } + ccdc_dev->hw_ops.set_image_window(&crop->c); + vpfe_dev->fmt.fmt.pix.width = crop->c.width; + vpfe_dev->fmt.fmt.pix.height = crop->c.height; + vpfe_dev->fmt.fmt.pix.bytesperline = + ccdc_dev->hw_ops.get_line_length(); + vpfe_dev->fmt.fmt.pix.sizeimage = + vpfe_dev->fmt.fmt.pix.bytesperline * + vpfe_dev->fmt.fmt.pix.height; + vpfe_dev->crop = crop->c; +unlock_out: + mutex_unlock(&vpfe_dev->lock); + return ret; +} + + +static long vpfe_param_handler(struct file *file, void *priv, + int cmd, void *param) +{ + struct vpfe_device *vpfe_dev = video_drvdata(file); + int ret = 0; + + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); + + if (vpfe_dev->started) { + /* only allowed if streaming is not started */ + v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n"); + return -EBUSY; + } + + ret = mutex_lock_interruptible(&vpfe_dev->lock); + if (ret) + return ret; + + switch (cmd) { + case VPFE_CMD_S_CCDC_RAW_PARAMS: + v4l2_warn(&vpfe_dev->v4l2_dev, + "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); + ret = ccdc_dev->hw_ops.set_params(param); + if (ret) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Error in setting parameters in CCDC\n"); + goto unlock_out; + } + if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) { + v4l2_err(&vpfe_dev->v4l2_dev, + "Invalid image format at CCDC\n"); + goto unlock_out; + } + break; + default: + ret = -EINVAL; + } +unlock_out: + mutex_unlock(&vpfe_dev->lock); + 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_queryctrl = vpfe_queryctrl, + .vidioc_g_ctrl = vpfe_g_ctrl, + .vidioc_s_ctrl = vpfe_s_ctrl, + .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_cropcap = vpfe_cropcap, + .vidioc_g_crop = vpfe_g_crop, + .vidioc_s_crop = vpfe_s_crop, + .vidioc_default = vpfe_param_handler, +}; + +static struct vpfe_device *vpfe_initialize(void) +{ + struct vpfe_device *vpfe_dev; + + /* Default number of buffers should be 3 */ + if ((numbuffers > 0) && + (numbuffers < config_params.min_numbuffers)) + numbuffers = config_params.min_numbuffers; + + /* + * Set buffer size to min buffers size if invalid buffer size is + * given + */ + if (bufsize < config_params.min_bufsize) + bufsize = config_params.min_bufsize; + + config_params.numbuffers = numbuffers; + + if (numbuffers) + config_params.device_bufsize = bufsize; + + /* Allocate memory for device objects */ + vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); + + return vpfe_dev; +} + +/* + * vpfe_probe : This function creates device entries by register + * itself to the V4L2 driver and initializes fields of each + * device objects + */ +static __init int vpfe_probe(struct platform_device *pdev) +{ + struct vpfe_subdev_info *sdinfo; + struct vpfe_config *vpfe_cfg; + struct resource *res1; + struct vpfe_device *vpfe_dev; + struct i2c_adapter *i2c_adap; + struct video_device *vfd; + int ret = -ENOMEM, i, j; + int num_subdevs = 0; + + /* Get the pointer to the device object */ + vpfe_dev = vpfe_initialize(); + + if (!vpfe_dev) { + v4l2_err(pdev->dev.driver, + "Failed to allocate memory for vpfe_dev\n"); + return ret; + } + + vpfe_dev->pdev = &pdev->dev; + + if (NULL == pdev->dev.platform_data) { + v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); + ret = -ENODEV; + goto probe_free_dev_mem; + } + + vpfe_cfg = pdev->dev.platform_data; + vpfe_dev->cfg = vpfe_cfg; + if (NULL == vpfe_cfg->ccdc || + NULL == vpfe_cfg->card_name || + NULL == vpfe_cfg->sub_devs) { + v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); + ret = -ENOENT; + goto probe_free_dev_mem; + } + + mutex_lock(&ccdc_lock); + /* Allocate memory for ccdc configuration */ + ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); + if (NULL == ccdc_cfg) { + v4l2_err(pdev->dev.driver, + "Memory allocation failed for ccdc_cfg\n"); + goto probe_free_dev_mem; + } + + strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); + /* Get VINT0 irq resource */ + res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res1) { + v4l2_err(pdev->dev.driver, + "Unable to get interrupt for VINT0\n"); + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; + } + vpfe_dev->ccdc_irq0 = res1->start; + + /* Get VINT1 irq resource */ + res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!res1) { + v4l2_err(pdev->dev.driver, + "Unable to get interrupt for VINT1\n"); + ret = -ENODEV; + goto probe_free_ccdc_cfg_mem; + } + vpfe_dev->ccdc_irq1 = res1->start; + + ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, + "vpfe_capture0", vpfe_dev); + + if (0 != ret) { + v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); + goto probe_free_ccdc_cfg_mem; + } + + /* Allocate memory for video device */ + vfd = video_device_alloc(); + if (NULL == vfd) { + ret = -ENOMEM; + v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); + goto probe_out_release_irq; + } + + /* Initialize field of video device */ + vfd->release = video_device_release; + vfd->fops = &vpfe_fops; + vfd->ioctl_ops = &vpfe_ioctl_ops; + vfd->tvnorms = 0; + vfd->current_norm = V4L2_STD_PAL; + vfd->v4l2_dev = &vpfe_dev->v4l2_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 */ + vpfe_dev->video_dev = vfd; + + ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); + if (ret) { + v4l2_err(pdev->dev.driver, + "Unable to register v4l2 device.\n"); + goto probe_out_video_release; + } + v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); + spin_lock_init(&vpfe_dev->irqlock); + spin_lock_init(&vpfe_dev->dma_queue_lock); + mutex_init(&vpfe_dev->lock); + + /* Initialize field of the device objects */ + vpfe_dev->numbuffers = config_params.numbuffers; + + /* Initialize prio member of device object */ + v4l2_prio_init(&vpfe_dev->prio); + /* register video device */ + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "trying to register vpfe device.\n"); + v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, + "video_dev=%x\n", (int)&vpfe_dev->video_dev); + vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = video_register_device(vpfe_dev->video_dev, + VFL_TYPE_GRABBER, -1); + + if (ret) { + v4l2_err(pdev->dev.driver, + "Unable to register video device.\n"); + goto probe_out_v4l2_unregister; + } + + v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpfe_dev); + /* set driver private data */ + video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); + i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); + num_subdevs = vpfe_cfg->num_subdevs; + vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, + GFP_KERNEL); + if (NULL == vpfe_dev->sd) { + v4l2_err(&vpfe_dev->v4l2_dev, + "unable to allocate memory for subdevice pointers\n"); + ret = -ENOMEM; + goto probe_out_video_unregister; + } + + for (i = 0; i < num_subdevs; i++) { + struct v4l2_input *inps; + + sdinfo = &vpfe_cfg->sub_devs[i]; + + /* Load up the subdevice */ + vpfe_dev->sd[i] = + v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, + i2c_adap, + sdinfo->name, + &sdinfo->board_info, + NULL); + if (vpfe_dev->sd[i]) { + v4l2_info(&vpfe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + sdinfo->name); + vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; + /* update tvnorms from the sub devices */ + for (j = 0; j < sdinfo->num_inputs; j++) { + inps = &sdinfo->inputs[j]; + vfd->tvnorms |= inps->std; + } + } else { + v4l2_info(&vpfe_dev->v4l2_dev, + "v4l2 sub device %s register fails\n", + sdinfo->name); + goto probe_sd_out; + } + } + + /* set first sub device as current one */ + vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; + + /* We have at least one sub device to work with */ + mutex_unlock(&ccdc_lock); + return 0; + +probe_sd_out: + kfree(vpfe_dev->sd); +probe_out_video_unregister: + video_unregister_device(vpfe_dev->video_dev); +probe_out_v4l2_unregister: + v4l2_device_unregister(&vpfe_dev->v4l2_dev); +probe_out_video_release: + if (!video_is_registered(vpfe_dev->video_dev)) + video_device_release(vpfe_dev->video_dev); +probe_out_release_irq: + free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); +probe_free_ccdc_cfg_mem: + mutex_unlock(&ccdc_lock); + kfree(ccdc_cfg); +probe_free_dev_mem: + kfree(vpfe_dev); + return ret; +} + +/* + * vpfe_remove : It un-register device from V4L2 driver + */ +static int __devexit vpfe_remove(struct platform_device *pdev) +{ + struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); + + v4l2_info(pdev->dev.driver, "vpfe_remove\n"); + + free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); + kfree(vpfe_dev->sd); + v4l2_device_unregister(&vpfe_dev->v4l2_dev); + video_unregister_device(vpfe_dev->video_dev); + kfree(vpfe_dev); + kfree(ccdc_cfg); + return 0; +} + +static int vpfe_suspend(struct device *dev) +{ + return 0; +} + +static int vpfe_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops vpfe_dev_pm_ops = { + .suspend = vpfe_suspend, + .resume = vpfe_resume, +}; + +static struct platform_driver vpfe_driver = { + .driver = { + .name = CAPTURE_DRV_NAME, + .owner = THIS_MODULE, + .pm = &vpfe_dev_pm_ops, + }, + .probe = vpfe_probe, + .remove = __devexit_p(vpfe_remove), +}; + +static __init int vpfe_init(void) +{ + printk(KERN_NOTICE "vpfe_init\n"); + /* Register driver to the kernel */ + return platform_driver_register(&vpfe_driver); +} + +/* + * vpfe_cleanup : This function un-registers device driver + */ +static void vpfe_cleanup(void) +{ + platform_driver_unregister(&vpfe_driver); +} + +module_init(vpfe_init); +module_exit(vpfe_cleanup); diff --git a/drivers/media/video/ti-media/vpif.c b/drivers/media/video/ti-media/vpif.c new file mode 100644 index 0000000..1f532e3 --- /dev/null +++ b/drivers/media/video/ti-media/vpif.c @@ -0,0 +1,296 @@ +/* + * vpif - DM646x Video Port Interface driver + * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) + * that receiveing video byte stream and two channels(2, 3) for video output. + * The hardware supports SDTV, HDTV formats, raw data capture. + * Currently, the driver supports NTSC and PAL standards. + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "vpif.h" + +MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); +MODULE_LICENSE("GPL"); + +#define VPIF_CH0_MAX_MODES (22) +#define VPIF_CH1_MAX_MODES (02) +#define VPIF_CH2_MAX_MODES (15) +#define VPIF_CH3_MAX_MODES (02) + +static resource_size_t res_len; +static struct resource *res; +spinlock_t vpif_lock; + +void __iomem *vpif_base; + +static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) +{ + if (val) + vpif_set_bit(reg, bit); + else + vpif_clr_bit(reg, bit); +} + +/* This structure is used to keep track of VPIF size register's offsets */ +struct vpif_registers { + u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; + u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; + u32 vanc1_size, width_mask, len_mask; + u8 max_modes; +}; + +static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { + /* Channel0 */ + { + VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, + VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, + VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, + VPIF_CH0_MAX_MODES, + }, + /* Channel1 */ + { + VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, + VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, + VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, + VPIF_CH1_MAX_MODES, + }, + /* Channel2 */ + { + VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, + VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, + VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, + VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, + VPIF_CH2_MAX_MODES + }, + /* Channel3 */ + { + VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, + VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, + VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, + VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, + VPIF_CH3_MAX_MODES + }, +}; + +/* vpif_set_mode_info: + * This function is used to set horizontal and vertical config parameters + * As per the standard in the channel, configure the values of L1, L3, + * L5, L7 L9, L11 in VPIF Register , also write width and height + */ +static void vpif_set_mode_info(const struct vpif_channel_config_params *config, + u8 channel_id, u8 config_channel_id) +{ + u32 value; + + value = (config->eav2sav & vpifregs[config_channel_id].width_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); + regw(value, vpifregs[channel_id].h_cfg); + + value = (config->l1 & vpifregs[config_channel_id].len_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->l3 & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg_00); + + value = (config->l5 & vpifregs[config_channel_id].len_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->l7 & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg_01); + + value = (config->l9 & vpifregs[config_channel_id].len_mask); + value <<= VPIF_CH_LEN_SHIFT; + value |= (config->l11 & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg_02); + + value = (config->vsize & vpifregs[config_channel_id].len_mask); + regw(value, vpifregs[channel_id].v_cfg); +} + +/* config_vpif_params + * Function to set the parameters of a channel + * Mainly modifies the channel ciontrol register + * It sets frame format, yc mux mode + */ +static void config_vpif_params(struct vpif_params *vpifparams, + u8 channel_id, u8 found) +{ + const struct vpif_channel_config_params *config = &vpifparams->std_info; + u32 value, ch_nip, reg; + u8 start, end; + int i; + + start = channel_id; + end = channel_id + found; + + for (i = start; i < end; i++) { + reg = vpifregs[i].ch_ctrl; + if (channel_id < 2) + ch_nip = VPIF_CAPTURE_CH_NIP; + else + ch_nip = VPIF_DISPLAY_CH_NIP; + + vpif_wr_bit(reg, ch_nip, config->frm_fmt); + vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); + vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, + vpifparams->video_params.storage_mode); + + /* Set raster scanning SDR Format */ + vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); + vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); + + if (channel_id > 1) /* Set the Pixel enable bit */ + vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); + else if (config->capture_format) { + /* Set the polarity of various pins */ + vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, + vpifparams->iface.fid_pol); + vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, + vpifparams->iface.vd_pol); + vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, + vpifparams->iface.hd_pol); + + value = regr(reg); + /* Set data width */ + value &= ((~(unsigned int)(0x3)) << + VPIF_CH_DATA_WIDTH_BIT); + value |= ((vpifparams->params.data_sz) << + VPIF_CH_DATA_WIDTH_BIT); + regw(value, reg); + } + + /* Write the pitch in the driver */ + regw((vpifparams->video_params.hpitch), + vpifregs[i].line_offset); + } +} + +/* vpif_set_video_params + * This function is used to set video parameters in VPIF register + */ +int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) +{ + const struct vpif_channel_config_params *config = &vpifparams->std_info; + int found = 1; + + vpif_set_mode_info(config, channel_id, channel_id); + if (!config->ycmux_mode) { + /* YC are on separate channels (HDTV formats) */ + vpif_set_mode_info(config, channel_id + 1, channel_id); + found = 2; + } + + config_vpif_params(vpifparams, channel_id, found); + + regw(0x80, VPIF_REQ_SIZE); + regw(0x01, VPIF_EMULATION_CTRL); + + return found; +} +EXPORT_SYMBOL(vpif_set_video_params); + +void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, + u8 channel_id) +{ + u32 value; + + value = 0x3F8 & (vbiparams->hstart0); + value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); + regw(value, vpifregs[channel_id].vanc0_strt); + + value = 0x3F8 & (vbiparams->hstart1); + value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); + regw(value, vpifregs[channel_id].vanc1_strt); + + value = 0x3F8 & (vbiparams->hsize0); + value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); + regw(value, vpifregs[channel_id].vanc0_size); + + value = 0x3F8 & (vbiparams->hsize1); + value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); + regw(value, vpifregs[channel_id].vanc1_size); + +} +EXPORT_SYMBOL(vpif_set_vbi_display_params); + +int vpif_channel_getfid(u8 channel_id) +{ + return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) + >> VPIF_CH_FID_SHIFT; +} +EXPORT_SYMBOL(vpif_channel_getfid); + +static int __init vpif_probe(struct platform_device *pdev) +{ + int status = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + res_len = res->end - res->start + 1; + + res = request_mem_region(res->start, res_len, res->name); + if (!res) + return -EBUSY; + + vpif_base = ioremap(res->start, res_len); + if (!vpif_base) { + status = -EBUSY; + goto fail; + } + + spin_lock_init(&vpif_lock); + dev_info(&pdev->dev, "vpif probe success\n"); + return 0; + +fail: + release_mem_region(res->start, res_len); + return status; +} + +static int __devexit vpif_remove(struct platform_device *pdev) +{ + iounmap(vpif_base); + release_mem_region(res->start, res_len); + return 0; +} + +static struct platform_driver vpif_driver = { + .driver = { + .name = "vpif", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(vpif_remove), + .probe = vpif_probe, +}; + +static void vpif_exit(void) +{ + platform_driver_unregister(&vpif_driver); +} + +static int __init vpif_init(void) +{ + return platform_driver_register(&vpif_driver); +} +subsys_initcall(vpif_init); +module_exit(vpif_exit); + diff --git a/drivers/media/video/ti-media/vpif.h b/drivers/media/video/ti-media/vpif.h new file mode 100644 index 0000000..188841b --- /dev/null +++ b/drivers/media/video/ti-media/vpif.h @@ -0,0 +1,642 @@ +/* + * VPIF header file + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef VPIF_H +#define VPIF_H + +#include +#include +#include +#include + +/* Maximum channel allowed */ +#define VPIF_NUM_CHANNELS (4) +#define VPIF_CAPTURE_NUM_CHANNELS (2) +#define VPIF_DISPLAY_NUM_CHANNELS (2) + +/* Macros to read/write registers */ +extern void __iomem *vpif_base; +extern spinlock_t vpif_lock; + +#define regr(reg) readl((reg) + vpif_base) +#define regw(value, reg) writel(value, (reg + vpif_base)) + +/* Register Addresss Offsets */ +#define VPIF_PID (0x0000) +#define VPIF_CH0_CTRL (0x0004) +#define VPIF_CH1_CTRL (0x0008) +#define VPIF_CH2_CTRL (0x000C) +#define VPIF_CH3_CTRL (0x0010) + +#define VPIF_INTEN (0x0020) +#define VPIF_INTEN_SET (0x0024) +#define VPIF_INTEN_CLR (0x0028) +#define VPIF_STATUS (0x002C) +#define VPIF_STATUS_CLR (0x0030) +#define VPIF_EMULATION_CTRL (0x0034) +#define VPIF_REQ_SIZE (0x0038) + +#define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040) +#define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044) +#define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048) +#define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c) +#define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050) +#define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054) +#define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058) +#define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c) +#define VPIF_CH0_SP_CFG (0x0060) +#define VPIF_CH0_IMG_ADD_OFST (0x0064) +#define VPIF_CH0_HANC_ADD_OFST (0x0068) +#define VPIF_CH0_H_CFG (0x006c) +#define VPIF_CH0_V_CFG_00 (0x0070) +#define VPIF_CH0_V_CFG_01 (0x0074) +#define VPIF_CH0_V_CFG_02 (0x0078) +#define VPIF_CH0_V_CFG_03 (0x007c) + +#define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080) +#define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084) +#define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088) +#define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c) +#define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090) +#define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094) +#define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098) +#define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c) +#define VPIF_CH1_SP_CFG (0x00a0) +#define VPIF_CH1_IMG_ADD_OFST (0x00a4) +#define VPIF_CH1_HANC_ADD_OFST (0x00a8) +#define VPIF_CH1_H_CFG (0x00ac) +#define VPIF_CH1_V_CFG_00 (0x00b0) +#define VPIF_CH1_V_CFG_01 (0x00b4) +#define VPIF_CH1_V_CFG_02 (0x00b8) +#define VPIF_CH1_V_CFG_03 (0x00bc) + +#define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0) +#define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4) +#define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8) +#define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc) +#define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0) +#define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4) +#define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8) +#define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc) +#define VPIF_CH2_SP_CFG (0x00e0) +#define VPIF_CH2_IMG_ADD_OFST (0x00e4) +#define VPIF_CH2_HANC_ADD_OFST (0x00e8) +#define VPIF_CH2_H_CFG (0x00ec) +#define VPIF_CH2_V_CFG_00 (0x00f0) +#define VPIF_CH2_V_CFG_01 (0x00f4) +#define VPIF_CH2_V_CFG_02 (0x00f8) +#define VPIF_CH2_V_CFG_03 (0x00fc) +#define VPIF_CH2_HANC0_STRT (0x0100) +#define VPIF_CH2_HANC0_SIZE (0x0104) +#define VPIF_CH2_HANC1_STRT (0x0108) +#define VPIF_CH2_HANC1_SIZE (0x010c) +#define VPIF_CH2_VANC0_STRT (0x0110) +#define VPIF_CH2_VANC0_SIZE (0x0114) +#define VPIF_CH2_VANC1_STRT (0x0118) +#define VPIF_CH2_VANC1_SIZE (0x011c) + +#define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140) +#define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144) +#define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148) +#define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c) +#define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150) +#define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154) +#define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158) +#define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c) +#define VPIF_CH3_SP_CFG (0x0160) +#define VPIF_CH3_IMG_ADD_OFST (0x0164) +#define VPIF_CH3_HANC_ADD_OFST (0x0168) +#define VPIF_CH3_H_CFG (0x016c) +#define VPIF_CH3_V_CFG_00 (0x0170) +#define VPIF_CH3_V_CFG_01 (0x0174) +#define VPIF_CH3_V_CFG_02 (0x0178) +#define VPIF_CH3_V_CFG_03 (0x017c) +#define VPIF_CH3_HANC0_STRT (0x0180) +#define VPIF_CH3_HANC0_SIZE (0x0184) +#define VPIF_CH3_HANC1_STRT (0x0188) +#define VPIF_CH3_HANC1_SIZE (0x018c) +#define VPIF_CH3_VANC0_STRT (0x0190) +#define VPIF_CH3_VANC0_SIZE (0x0194) +#define VPIF_CH3_VANC1_STRT (0x0198) +#define VPIF_CH3_VANC1_SIZE (0x019c) + +#define VPIF_IODFT_CTRL (0x01c0) + +/* Functions for bit Manipulation */ +static inline void vpif_set_bit(u32 reg, u32 bit) +{ + regw((regr(reg)) | (0x01 << bit), reg); +} + +static inline void vpif_clr_bit(u32 reg, u32 bit) +{ + regw(((regr(reg)) & ~(0x01 << bit)), reg); +} + +/* Macro for Generating mask */ +#ifdef GENERATE_MASK +#undef GENERATE_MASK +#endif + +#define GENERATE_MASK(bits, pos) \ + ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos) + +/* Bit positions in the channel control registers */ +#define VPIF_CH_DATA_MODE_BIT (2) +#define VPIF_CH_YC_MUX_BIT (3) +#define VPIF_CH_SDR_FMT_BIT (4) +#define VPIF_CH_HANC_EN_BIT (8) +#define VPIF_CH_VANC_EN_BIT (9) + +#define VPIF_CAPTURE_CH_NIP (10) +#define VPIF_DISPLAY_CH_NIP (11) + +#define VPIF_DISPLAY_PIX_EN_BIT (10) + +#define VPIF_CH_INPUT_FIELD_FRAME_BIT (12) + +#define VPIF_CH_FID_POLARITY_BIT (15) +#define VPIF_CH_V_VALID_POLARITY_BIT (14) +#define VPIF_CH_H_VALID_POLARITY_BIT (13) +#define VPIF_CH_DATA_WIDTH_BIT (28) + +#define VPIF_CH_CLK_EDGE_CTRL_BIT (31) + +/* Mask various length */ +#define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0) +#define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0) +#define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0) +#define VPIF_CH_LEN_SHIFT (16) + +/* VPIF masks for registers */ +#define VPIF_REQ_SIZE_MASK (0x1ff) + +/* bit posotion of interrupt vpif_ch_intr register */ +#define VPIF_INTEN_FRAME_CH0 (0x00000001) +#define VPIF_INTEN_FRAME_CH1 (0x00000002) +#define VPIF_INTEN_FRAME_CH2 (0x00000004) +#define VPIF_INTEN_FRAME_CH3 (0x00000008) + +/* bit position of clock and channel enable in vpif_chn_ctrl register */ + +#define VPIF_CH0_CLK_EN (0x00000002) +#define VPIF_CH0_EN (0x00000001) +#define VPIF_CH1_CLK_EN (0x00000002) +#define VPIF_CH1_EN (0x00000001) +#define VPIF_CH2_CLK_EN (0x00000002) +#define VPIF_CH2_EN (0x00000001) +#define VPIF_CH3_CLK_EN (0x00000002) +#define VPIF_CH3_EN (0x00000001) +#define VPIF_CH_CLK_EN (0x00000002) +#define VPIF_CH_EN (0x00000001) + +#define VPIF_INT_TOP (0x00) +#define VPIF_INT_BOTTOM (0x01) +#define VPIF_INT_BOTH (0x02) + +#define VPIF_CH0_INT_CTRL_SHIFT (6) +#define VPIF_CH1_INT_CTRL_SHIFT (6) +#define VPIF_CH2_INT_CTRL_SHIFT (6) +#define VPIF_CH3_INT_CTRL_SHIFT (6) +#define VPIF_CH_INT_CTRL_SHIFT (6) + +/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ +#define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) + +/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ +#define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL)) + +/* enabled interrupt on both the fields on vpid_ch0_ctrl register */ +#define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL)) + +/* enabled interrupt on both the fields on vpid_ch1_ctrl register */ +#define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\ + (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL)) + +#define VPIF_CH_FID_MASK (0x20) +#define VPIF_CH_FID_SHIFT (5) + +#define VPIF_NTSC_VBI_START_FIELD0 (1) +#define VPIF_NTSC_VBI_START_FIELD1 (263) +#define VPIF_PAL_VBI_START_FIELD0 (624) +#define VPIF_PAL_VBI_START_FIELD1 (311) + +#define VPIF_NTSC_HBI_START_FIELD0 (1) +#define VPIF_NTSC_HBI_START_FIELD1 (263) +#define VPIF_PAL_HBI_START_FIELD0 (624) +#define VPIF_PAL_HBI_START_FIELD1 (311) + +#define VPIF_NTSC_VBI_COUNT_FIELD0 (20) +#define VPIF_NTSC_VBI_COUNT_FIELD1 (19) +#define VPIF_PAL_VBI_COUNT_FIELD0 (24) +#define VPIF_PAL_VBI_COUNT_FIELD1 (25) + +#define VPIF_NTSC_HBI_COUNT_FIELD0 (263) +#define VPIF_NTSC_HBI_COUNT_FIELD1 (262) +#define VPIF_PAL_HBI_COUNT_FIELD0 (312) +#define VPIF_PAL_HBI_COUNT_FIELD1 (313) + +#define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720) +#define VPIF_PAL_VBI_SAMPLES_PER_LINE (720) +#define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268) +#define VPIF_PAL_HBI_SAMPLES_PER_LINE (280) + +#define VPIF_CH_VANC_EN (0x20) +#define VPIF_DMA_REQ_SIZE (0x080) +#define VPIF_EMULATION_DISABLE (0x01) + +extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS]; + +/* inline function to enable/disable channel0 */ +static inline void enable_channel0(int enable) +{ + if (enable) + regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL); + else + regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL); +} + +/* inline function to enable/disable channel1 */ +static inline void enable_channel1(int enable) +{ + if (enable) + regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL); + else + regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL); +} + +/* inline function to enable interrupt for channel0 */ +static inline void channel0_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to enable interrupt for channel1 */ +static inline void channel1_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to set buffer addresses in case of Y/C non mux mode */ +static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); +} + +/* inline function to set buffer addresses in VPIF registers for video data */ +static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); +} + +static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + + regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); +} + +static inline void ch0_set_vbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC); + regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC); +} + +static inline void ch0_set_hbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC); + regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC); +} + +static inline void ch1_set_vbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC); + regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC); +} + +static inline void ch1_set_hbi_addr(unsigned long top_vbi, + unsigned long btm_vbi, unsigned long a, unsigned long b) +{ + regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC); + regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC); +} + +/* Inline function to enable raw vbi in the given channel */ +static inline void disable_raw_feature(u8 channel_id, u8 index) +{ + u32 ctrl_reg; + if (0 == channel_id) + ctrl_reg = VPIF_CH0_CTRL; + else + ctrl_reg = VPIF_CH1_CTRL; + + if (1 == index) + vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); + else + vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); +} + +static inline void enable_raw_feature(u8 channel_id, u8 index) +{ + u32 ctrl_reg; + if (0 == channel_id) + ctrl_reg = VPIF_CH0_CTRL; + else + ctrl_reg = VPIF_CH1_CTRL; + + if (1 == index) + vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); + else + vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); +} + +/* inline function to enable/disable channel2 */ +static inline void enable_channel2(int enable) +{ + if (enable) { + regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); + regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL); + } else { + regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); + regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL); + } +} + +/* inline function to enable/disable channel3 */ +static inline void enable_channel3(int enable) +{ + if (enable) { + regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); + regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL); + } else { + regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); + regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL); + } +} + +/* inline function to enable interrupt for channel2 */ +static inline void channel2_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to enable interrupt for channel3 */ +static inline void channel3_intr_enable(int enable) +{ + unsigned long flags; + + spin_lock_irqsave(&vpif_lock, flags); + + if (enable) { + regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); + + regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), + VPIF_INTEN_SET); + } else { + regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN); + regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), + VPIF_INTEN_SET); + } + spin_unlock_irqrestore(&vpif_lock, flags); +} + +/* inline function to enable raw vbi data for channel2 */ +static inline void channel2_raw_enable(int enable, u8 index) +{ + u32 mask; + + if (1 == index) + mask = VPIF_CH_VANC_EN_BIT; + else + mask = VPIF_CH_HANC_EN_BIT; + + if (enable) + vpif_set_bit(VPIF_CH2_CTRL, mask); + else + vpif_clr_bit(VPIF_CH2_CTRL, mask); +} + +/* inline function to enable raw vbi data for channel3*/ +static inline void channel3_raw_enable(int enable, u8 index) +{ + u32 mask; + + if (1 == index) + mask = VPIF_CH_VANC_EN_BIT; + else + mask = VPIF_CH_HANC_EN_BIT; + + if (enable) + vpif_set_bit(VPIF_CH3_CTRL, mask); + else + vpif_clr_bit(VPIF_CH3_CTRL, mask); +} + +/* inline function to set buffer addresses in case of Y/C non mux mode */ +static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); +} + +/* inline function to set buffer addresses in VPIF registers for video data */ +static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); +} + +static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); + regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); + regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); + regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); +} + +/* inline function to set buffer addresses in VPIF registers for vbi data */ +static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); + regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); +} + +static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) +{ + regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); + regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); +} + +#define VPIF_MAX_NAME (30) + +/* This structure will store size parameters as per the mode selected by user */ +struct vpif_channel_config_params { + char name[VPIF_MAX_NAME]; /* Name of the mode */ + u16 width; /* Indicates width of the image */ + u16 height; /* Indicates height of the image */ + u8 fps; + u8 frm_fmt; /* Indicates whether this is interlaced + * or progressive format */ + u8 ycmux_mode; /* Indicates whether this mode requires + * single or two channels */ + u16 eav2sav; /* length of sav 2 eav */ + u16 sav2eav; /* length of sav 2 eav */ + u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ + u16 vsize; /* Vertical size of the image */ + u8 capture_format; /* Indicates whether capture format + * is in BT or in CCD/CMOS */ + u8 vbi_supported; /* Indicates whether this mode + * supports capturing vbi or not */ + u8 hd_sd; + v4l2_std_id stdid; +}; + +struct vpif_video_params; +struct vpif_params; +struct vpif_vbi_params; + +int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id); +void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, + u8 channel_id); +int vpif_channel_getfid(u8 channel_id); + +enum data_size { + _8BITS = 0, + _10BITS, + _12BITS, +}; + +/* Structure for vpif parameters for raw vbi data */ +struct vpif_vbi_params { + __u32 hstart0; /* Horizontal start of raw vbi data for first field */ + __u32 vstart0; /* Vertical start of raw vbi data for first field */ + __u32 hsize0; /* Horizontal size of raw vbi data for first field */ + __u32 vsize0; /* Vertical size of raw vbi data for first field */ + __u32 hstart1; /* Horizontal start of raw vbi data for second field */ + __u32 vstart1; /* Vertical start of raw vbi data for second field */ + __u32 hsize1; /* Horizontal size of raw vbi data for second field */ + __u32 vsize1; /* Vertical size of raw vbi data for second field */ +}; + +/* structure for vpif parameters */ +struct vpif_video_params { + __u8 storage_mode; /* Indicates field or frame mode */ + unsigned long hpitch; + v4l2_std_id stdid; +}; + +struct vpif_params { + struct vpif_interface iface; + struct vpif_video_params video_params; + struct vpif_channel_config_params std_info; + union param { + struct vpif_vbi_params vbi_params; + enum data_size data_sz; + } params; +}; + +#endif /* End of #ifndef VPIF_H */ + diff --git a/drivers/media/video/ti-media/vpif_capture.c b/drivers/media/video/ti-media/vpif_capture.c new file mode 100644 index 0000000..a50a6d0 --- /dev/null +++ b/drivers/media/video/ti-media/vpif_capture.c @@ -0,0 +1,2169 @@ +/* + * Copyright (C) 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 + * + * TODO : add support for VBI & HBI data service + * add static buffer allocation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpif_capture.h" +#include "vpif.h" + +MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); +MODULE_LICENSE("GPL"); + +#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) +#define vpif_dbg(level, debug, fmt, arg...) \ + v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) + +static int debug = 1; +static u32 ch0_numbuffers = 3; +static u32 ch1_numbuffers = 3; +static u32 ch0_bufsize = 1920 * 1080 * 2; +static u32 ch1_bufsize = 720 * 576 * 2; + +module_param(debug, int, 0644); +module_param(ch0_numbuffers, uint, S_IRUGO); +module_param(ch1_numbuffers, uint, S_IRUGO); +module_param(ch0_bufsize, uint, S_IRUGO); +module_param(ch1_bufsize, uint, S_IRUGO); + +MODULE_PARM_DESC(debug, "Debug level 0-1"); +MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)"); +MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)"); +MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)"); +MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)"); + +static struct vpif_config_params config_params = { + .min_numbuffers = 3, + .numbuffers[0] = 3, + .numbuffers[1] = 3, + .min_bufsize[0] = 720 * 480 * 2, + .min_bufsize[1] = 720 * 480 * 2, + .channel_bufsize[0] = 1920 * 1080 * 2, + .channel_bufsize[1] = 720 * 576 * 2, +}; + +/* global variables */ +static struct vpif_device vpif_obj = { {NULL} }; +static struct device *vpif_dev; + +/** + * ch_params: video standard configuration parameters for vpif + */ +static const struct vpif_channel_config_params ch_params[] = { + { + "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, + 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, + }, + { + "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, + 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, + }, +}; + +/** + * vpif_uservirt_to_phys : translate user/virtual address to phy address + * @virtp: user/virtual address + * + * This inline function is used to convert user space virtual address to + * physical address. + */ +static inline u32 vpif_uservirt_to_phys(u32 virtp) +{ + unsigned long physp = 0; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + + vma = find_vma(mm, virtp); + + /* For kernel direct-mapped memory, take the easy way */ + if (virtp >= PAGE_OFFSET) + physp = virt_to_phys((void *)virtp); + else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) + /** + * this will catch, kernel-allocated, mmaped-to-usermode + * addresses + */ + physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); + else { + /* otherwise, use get_user_pages() for general userland pages */ + int res, nr_pages = 1; + struct page *pages; + + down_read(¤t->mm->mmap_sem); + + res = get_user_pages(current, current->mm, + virtp, nr_pages, 1, 0, &pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (res == nr_pages) + physp = __pa(page_address(&pages[0]) + + (virtp & ~PAGE_MASK)); + else { + vpif_err("get_user_pages failed\n"); + return 0; + } + } + return physp; +} + +/** + * buffer_prepare : callback function for buffer prepare + * @q : buffer queue ptr + * @vb: ptr to video buffer + * @field: field info + * + * This is the callback function for buffer prepare when videobuf_qbuf() + * function is called. The buffer is prepared and user space virtual address + * or user address is converted into physical address + */ +static int vpif_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + unsigned long addr; + + + vpif_dbg(2, debug, "vpif_buffer_prepare\n"); + + common = &ch->common[VPIF_VIDEO_INDEX]; + + /* 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; + vb->field = field; + } + vb->state = VIDEOBUF_PREPARED; + /** + * if user pointer memory mechanism is used, get the physical + * address of the buffer + */ + if (V4L2_MEMORY_USERPTR == common->memory) { + if (0 == vb->baddr) { + vpif_dbg(1, debug, "buffer address is 0\n"); + return -EINVAL; + + } + vb->boff = vpif_uservirt_to_phys(vb->baddr); + if (!IS_ALIGNED(vb->boff, 8)) + goto exit; + } + + addr = vb->boff; + if (q->streaming) { + if (!IS_ALIGNED((addr + common->ytop_off), 8) || + !IS_ALIGNED((addr + common->ybtm_off), 8) || + !IS_ALIGNED((addr + common->ctop_off), 8) || + !IS_ALIGNED((addr + common->cbtm_off), 8)) + goto exit; + } + return 0; +exit: + vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n"); + return -EINVAL; +} + +/** + * vpif_buffer_setup : Callback function for buffer setup. + * @q: buffer queue ptr + * @count: number of buffers + * @size: size of the buffer + * + * This callback function is called when reqbuf() is called to adjust + * the buffer count and buffer size + */ +static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_buffer_setup\n"); + + /* If memory type is not mmap, return */ + if (V4L2_MEMORY_MMAP != common->memory) + return 0; + + /* Calculate the size of the buffer */ + *size = config_params.channel_bufsize[ch->channel_id]; + + if (*count < config_params.min_numbuffers) + *count = config_params.min_numbuffers; + return 0; +} + +/** + * vpif_buffer_queue : Callback function to add buffer to DMA queue + * @q: ptr to videobuf_queue + * @vb: ptr to videobuf_buffer + */ +static void vpif_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_buffer_queue\n"); + + /* add the buffer to the DMA queue */ + list_add_tail(&vb->queue, &common->dma_queue); + /* Change state of the buffer */ + vb->state = VIDEOBUF_QUEUED; +} + +/** + * vpif_buffer_release : Callback function to free buffer + * @q: buffer queue ptr + * @vb: ptr to video buffer + * + * This function is called from the videobuf layer to free memory + * allocated to the buffers + */ +static void vpif_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + /* Get the file handle object and channel object */ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + videobuf_dma_contig_free(q, vb); + vb->state = VIDEOBUF_NEEDS_INIT; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpif_buffer_setup, + .buf_prepare = vpif_buffer_prepare, + .buf_queue = vpif_buffer_queue, + .buf_release = vpif_buffer_release, +}; + +static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = { + {1, 1} +}; + +/** + * vpif_process_buffer_complete: process a completed buffer + * @common: ptr to common channel object + * + * This function time stamp the buffer and mark it as DONE. It also + * wake up any process waiting on the QUEUE and set the next buffer + * as current + */ +static void vpif_process_buffer_complete(struct common_obj *common) +{ + do_gettimeofday(&common->cur_frm->ts); + common->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&common->cur_frm->done); + /* Make curFrm pointing to nextFrm */ + common->cur_frm = common->next_frm; +} + +/** + * vpif_schedule_next_buffer: set next buffer address for capture + * @common : ptr to common channel object + * + * This function will get next buffer from the dma queue and + * set the buffer address in the vpif register for capture. + * the buffer is marked active + */ +static void vpif_schedule_next_buffer(struct common_obj *common) +{ + unsigned long addr = 0; + + common->next_frm = list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&common->next_frm->queue); + common->next_frm->state = VIDEOBUF_ACTIVE; + if (V4L2_MEMORY_USERPTR == common->memory) + addr = common->next_frm->boff; + else + addr = videobuf_to_dma_contig(common->next_frm); + + /* Set top and bottom field addresses in VPIF registers */ + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); +} + +/** + * vpif_channel_isr : ISR handler for vpif capture + * @irq: irq number + * @dev_id: dev_id ptr + * + * It changes status of the captured buffer, takes next buffer from the queue + * and sets its address in VPIF registers + */ +static irqreturn_t vpif_channel_isr(int irq, void *dev_id) +{ + struct vpif_device *dev = &vpif_obj; + struct common_obj *common; + struct channel_obj *ch; + enum v4l2_field field; + int channel_id = 0; + int fid = -1, i; + + channel_id = *(int *)(dev_id); + ch = dev->dev[channel_id]; + + field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; + + for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { + common = &ch->common[i]; + /* skip If streaming is not started in this channel */ + if (0 == common->started) + continue; + + /* Check the field format */ + if (1 == ch->vpifparams.std_info.frm_fmt) { + /* Progressive mode */ + if (list_empty(&common->dma_queue)) + continue; + + if (!channel_first_int[i][channel_id]) + vpif_process_buffer_complete(common); + + channel_first_int[i][channel_id] = 0; + + vpif_schedule_next_buffer(common); + + + channel_first_int[i][channel_id] = 0; + } else { + /** + * Interlaced mode. If it is first interrupt, ignore + * it + */ + if (channel_first_int[i][channel_id]) { + channel_first_int[i][channel_id] = 0; + continue; + } + if (0 == i) { + ch->field_id ^= 1; + /* Get field id from VPIF registers */ + fid = vpif_channel_getfid(ch->channel_id); + if (fid != ch->field_id) { + /** + * If field id does not match stored + * field id, make them in sync + */ + if (0 == fid) + ch->field_id = fid; + return IRQ_HANDLED; + } + } + /* device field id and local field id are in sync */ + if (0 == fid) { + /* this is even field */ + if (common->cur_frm == common->next_frm) + continue; + + /* mark the current buffer as done */ + vpif_process_buffer_complete(common); + } else if (1 == fid) { + /* odd field */ + if (list_empty(&common->dma_queue) || + (common->cur_frm != common->next_frm)) + continue; + + vpif_schedule_next_buffer(common); + } + } + } + return IRQ_HANDLED; +} + +/** + * vpif_update_std_info() - update standard related info + * @ch: ptr to channel object + * + * For a given standard selected by application, update values + * in the device data structures + */ +static int vpif_update_std_info(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_params *vpifparams = &ch->vpifparams; + const struct vpif_channel_config_params *config; + struct vpif_channel_config_params *std_info; + struct video_obj *vid_ch = &ch->video; + int index; + + vpif_dbg(2, debug, "vpif_update_std_info\n"); + + std_info = &vpifparams->std_info; + + for (index = 0; index < ARRAY_SIZE(ch_params); index++) { + config = &ch_params[index]; + if (config->stdid & vid_ch->stdid) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } + + /* standard not found */ + if (index == ARRAY_SIZE(ch_params)) + return -EINVAL; + + common->fmt.fmt.pix.width = std_info->width; + common->width = std_info->width; + common->fmt.fmt.pix.height = std_info->height; + common->height = std_info->height; + common->fmt.fmt.pix.bytesperline = std_info->width; + vpifparams->video_params.hpitch = std_info->width; + vpifparams->video_params.storage_mode = std_info->frm_fmt; + return 0; +} + +/** + * vpif_calculate_offsets : This function calculates buffers offsets + * @ch : ptr to channel object + * + * This function calculates buffer offsets for Y and C in the top and + * bottom field + */ +static void vpif_calculate_offsets(struct channel_obj *ch) +{ + unsigned int hpitch, vpitch, sizeimage; + struct video_obj *vid_ch = &(ch->video); + struct vpif_params *vpifparams = &ch->vpifparams; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + enum v4l2_field field = common->fmt.fmt.pix.field; + + vpif_dbg(2, debug, "vpif_calculate_offsets\n"); + + if (V4L2_FIELD_ANY == field) { + if (vpifparams->std_info.frm_fmt) + vid_ch->buf_field = V4L2_FIELD_NONE; + else + vid_ch->buf_field = V4L2_FIELD_INTERLACED; + } else + vid_ch->buf_field = common->fmt.fmt.pix.field; + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = common->fmt.fmt.pix.sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + hpitch = common->fmt.fmt.pix.bytesperline; + vpitch = sizeimage / (hpitch * 2); + + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { + /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ + common->ytop_off = 0; + common->ybtm_off = hpitch; + common->ctop_off = sizeimage / 2; + common->cbtm_off = sizeimage / 2 + hpitch; + } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { + /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ + common->ytop_off = 0; + common->ybtm_off = sizeimage / 4; + common->ctop_off = sizeimage / 2; + common->cbtm_off = common->ctop_off + sizeimage / 4; + } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { + /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ + common->ybtm_off = 0; + common->ytop_off = sizeimage / 4; + common->cbtm_off = sizeimage / 2; + common->ctop_off = common->cbtm_off + sizeimage / 4; + } + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) + vpifparams->video_params.storage_mode = 1; + else + vpifparams->video_params.storage_mode = 0; + + if (1 == vpifparams->std_info.frm_fmt) + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + else { + if ((field == V4L2_FIELD_ANY) + || (field == V4L2_FIELD_INTERLACED)) + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline * 2; + else + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + } + + ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid; +} + +/** + * vpif_config_format: configure default frame format in the device + * ch : ptr to channel object + */ +static void vpif_config_format(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_config_format\n"); + + common->fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (config_params.numbuffers[ch->channel_id] == 0) + common->memory = V4L2_MEMORY_USERPTR; + else + common->memory = V4L2_MEMORY_MMAP; + + common->fmt.fmt.pix.sizeimage + = config_params.channel_bufsize[ch->channel_id]; + + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) + common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; + else + common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; + common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +} + +/** + * vpif_get_default_field() - Get default field type based on interface + * @vpif_params - ptr to vpif params + */ +static inline enum v4l2_field vpif_get_default_field( + struct vpif_interface *iface) +{ + return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : + V4L2_FIELD_INTERLACED; +} + +/** + * vpif_check_format() - check given pixel format for compatibility + * @ch - channel ptr + * @pixfmt - Given pixel format + * @update - update the values as per hardware requirement + * + * Check the application pixel format for S_FMT and update the input + * values as per hardware limits for TRY_FMT. The default pixel and + * field format is selected based on interface type. + */ +static int vpif_check_format(struct channel_obj *ch, + struct v4l2_pix_format *pixfmt, + int update) +{ + struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); + struct vpif_params *vpif_params = &ch->vpifparams; + enum v4l2_field field = pixfmt->field; + u32 sizeimage, hpitch, vpitch; + int ret = -EINVAL; + + vpif_dbg(2, debug, "vpif_check_format\n"); + /** + * first check for the pixel format. If if_type is Raw bayer, + * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only + * V4L2_PIX_FMT_YUV422P is supported + */ + if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) { + if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) { + if (!update) { + vpif_dbg(2, debug, "invalid pix format\n"); + goto exit; + } + pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8; + } + } else { + if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) { + if (!update) { + vpif_dbg(2, debug, "invalid pixel format\n"); + goto exit; + } + pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P; + } + } + + if (!(VPIF_VALID_FIELD(field))) { + if (!update) { + vpif_dbg(2, debug, "invalid field format\n"); + goto exit; + } + /** + * By default use FIELD_NONE for RAW Bayer capture + * and FIELD_INTERLACED for other interfaces + */ + field = vpif_get_default_field(&vpif_params->iface); + } else if (field == V4L2_FIELD_ANY) + /* unsupported field. Use default */ + field = vpif_get_default_field(&vpif_params->iface); + + /* validate the hpitch */ + hpitch = pixfmt->bytesperline; + if (hpitch < vpif_params->std_info.width) { + if (!update) { + vpif_dbg(2, debug, "invalid hpitch\n"); + goto exit; + } + hpitch = vpif_params->std_info.width; + } + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = pixfmt->sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + vpitch = sizeimage / (hpitch * 2); + + /* validate the vpitch */ + if (vpitch < vpif_params->std_info.height) { + if (!update) { + vpif_dbg(2, debug, "Invalid vpitch\n"); + goto exit; + } + vpitch = vpif_params->std_info.height; + } + + /* Check for 8 byte alignment */ + if (!ALIGN(hpitch, 8)) { + if (!update) { + vpif_dbg(2, debug, "invalid pitch alignment\n"); + goto exit; + } + /* adjust to next 8 byte boundary */ + hpitch = (((hpitch + 7) / 8) * 8); + } + /* if update is set, modify the bytesperline and sizeimage */ + if (update) { + pixfmt->bytesperline = hpitch; + pixfmt->sizeimage = hpitch * vpitch * 2; + } + /** + * Image width and height is always based on current standard width and + * height + */ + pixfmt->width = common->fmt.fmt.pix.width; + pixfmt->height = common->fmt.fmt.pix.height; + return 0; +exit: + return ret; +} + +/** + * vpif_config_addr() - function to configure buffer address in vpif + * @ch - channel ptr + * @muxmode - channel mux mode + */ +static void vpif_config_addr(struct channel_obj *ch, int muxmode) +{ + struct common_obj *common; + + vpif_dbg(2, debug, "vpif_config_addr\n"); + + common = &(ch->common[VPIF_VIDEO_INDEX]); + + if (VPIF_CHANNEL1_VIDEO == ch->channel_id) + common->set_addr = ch1_set_videobuf_addr; + else if (2 == muxmode) + common->set_addr = ch0_set_videobuf_addr_yc_nmux; + else + common->set_addr = ch0_set_videobuf_addr; +} + +/** + * vpfe_mmap : It is used to map kernel space buffers into user spaces + * @filep: file pointer + * @vma: ptr to vm_area_struct + */ +static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) +{ + /* Get the channel object and file handle object */ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); + + vpif_dbg(2, debug, "vpif_mmap\n"); + + return videobuf_mmap_mapper(&common->buffer_queue, vma); +} + +/** + * vpif_poll: It is used for select/poll system call + * @filep: file pointer + * @wait: poll table to wait + */ +static unsigned int vpif_poll(struct file *filep, poll_table * wait) +{ + int err = 0; + struct vpif_fh *fh = filep->private_data; + struct channel_obj *channel = fh->channel; + struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]); + + vpif_dbg(2, debug, "vpif_poll\n"); + + if (common->started) + err = videobuf_poll_stream(filep, &common->buffer_queue, wait); + + return 0; +} + +/** + * vpif_open : vpif open handler + * @filep: file ptr + * + * It creates object of file handle structure and stores it in private_data + * member of filepointer + */ +static int vpif_open(struct file *filep) +{ + struct vpif_capture_config *config = vpif_dev->platform_data; + struct video_device *vdev = video_devdata(filep); + struct common_obj *common; + struct video_obj *vid_ch; + struct channel_obj *ch; + struct vpif_fh *fh; + int i, ret = 0; + + vpif_dbg(2, debug, "vpif_open\n"); + + ch = video_get_drvdata(vdev); + + vid_ch = &ch->video; + common = &ch->common[VPIF_VIDEO_INDEX]; + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + if (NULL == ch->curr_subdev_info) { + /** + * search through the sub device to see a registered + * sub device and make it as current sub device + */ + for (i = 0; i < config->subdev_count; i++) { + if (vpif_obj.sd[i]) { + /* the sub device is registered */ + ch->curr_subdev_info = &config->subdev_info[i]; + /* make first input as the current input */ + vid_ch->input_idx = 0; + break; + } + } + if (i == config->subdev_count) { + vpif_err("No sub device registered\n"); + ret = -ENOENT; + goto exit; + } + } + + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL); + if (NULL == fh) { + vpif_err("unable to allocate memory for file handle object\n"); + ret = -ENOMEM; + goto exit; + } + + /* store pointer to fh in private_data member of filep */ + filep->private_data = fh; + fh->channel = ch; + fh->initialized = 0; + /* If decoder is not initialized. initialize it */ + if (!ch->initialized) { + fh->initialized = 1; + ch->initialized = 1; + memset(&(ch->vpifparams), 0, sizeof(struct vpif_params)); + } + /* Increment channel usrs counter */ + ch->usrs++; + /* Set io_allowed member to false */ + fh->io_allowed[VPIF_VIDEO_INDEX] = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&ch->prio, &fh->prio); +exit: + mutex_unlock(&common->lock); + return ret; +} + +/** + * vpif_release : function to clean up file close + * @filep: file pointer + * + * This function deletes buffer queue, frees the buffers and the vpfe file + * handle + */ +static int vpif_release(struct file *filep) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + vpif_dbg(2, debug, "vpif_release\n"); + + common = &ch->common[VPIF_VIDEO_INDEX]; + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + /* if this instance is doing IO */ + if (fh->io_allowed[VPIF_VIDEO_INDEX]) { + /* Reset io_usrs member of channel object */ + common->io_usrs = 0; + /* Disable channel as per its device type and channel id */ + if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { + enable_channel0(0); + channel0_intr_enable(0); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel1(0); + channel1_intr_enable(0); + } + common->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&common->buffer_queue); + videobuf_mmap_free(&common->buffer_queue); + } + + /* Decrement channel usrs counter */ + ch->usrs--; + + /* unlock mutex on channel object */ + mutex_unlock(&common->lock); + + /* Close the priority */ + v4l2_prio_close(&ch->prio, &fh->prio); + + if (fh->initialized) + ch->initialized = 0; + + filep->private_data = NULL; + kfree(fh); + return 0; +} + +/** + * vpif_reqbufs() - request buffer handler + * @file: file ptr + * @priv: file handle + * @reqbuf: request buffer structure ptr + */ +static int vpif_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbuf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + u8 index = 0; + int ret = 0; + + vpif_dbg(2, debug, "vpif_reqbufs\n"); + + /** + * This file handle has not initialized the channel, + * It is not allowed to do settings + */ + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) + || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) + return -EINVAL; + + index = VPIF_VIDEO_INDEX; + + common = &ch->common[index]; + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + if (0 != common->io_usrs) { + ret = -EBUSY; + goto reqbuf_exit; + } + + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&common->buffer_queue, + &video_qops, NULL, + &common->irqlock, + reqbuf->type, + common->fmt.fmt.pix.field, + sizeof(struct videobuf_buffer), fh); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed[index] = 1; + /* Increment io usrs member of channel object to 1 */ + common->io_usrs = 1; + /* Store type of memory requested in channel object */ + common->memory = reqbuf->memory; + INIT_LIST_HEAD(&common->dma_queue); + + /* Allocate buffers */ + ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); + +reqbuf_exit: + mutex_unlock(&common->lock); + return ret; +} + +/** + * vpif_querybuf() - query buffer handler + * @file: file ptr + * @priv: file handle + * @buf: v4l2 buffer structure ptr + */ +static int vpif_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_querybuf\n"); + + if (common->fmt.type != buf->type) + return -EINVAL; + + if (common->memory != V4L2_MEMORY_MMAP) { + vpif_dbg(1, debug, "Invalid memory\n"); + return -EINVAL; + } + + return videobuf_querybuf(&common->buffer_queue, buf); +} + +/** + * vpif_qbuf() - query buffer handler + * @file: file ptr + * @priv: file handle + * @buf: v4l2 buffer structure ptr + */ +static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_buffer tbuf = *buf; + struct videobuf_buffer *buf1; + unsigned long addr = 0; + unsigned long flags; + int ret = 0; + + vpif_dbg(2, debug, "vpif_qbuf\n"); + + if (common->fmt.type != tbuf.type) { + vpif_err("invalid buffer type\n"); + return -EINVAL; + } + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh io not allowed \n"); + return -EACCES; + } + + if (!(list_empty(&common->dma_queue)) || + (common->cur_frm != common->next_frm) || + !common->started || + (common->started && (0 == ch->field_id))) + return videobuf_qbuf(&common->buffer_queue, buf); + + /* bufferqueue is empty store buffer address in VPIF registers */ + mutex_lock(&common->buffer_queue.vb_lock); + buf1 = common->buffer_queue.bufs[tbuf.index]; + + if ((buf1->state == VIDEOBUF_QUEUED) || + (buf1->state == VIDEOBUF_ACTIVE)) { + vpif_err("invalid state\n"); + goto qbuf_exit; + } + + switch (buf1->memory) { + case V4L2_MEMORY_MMAP: + if (buf1->baddr == 0) + goto qbuf_exit; + break; + + case V4L2_MEMORY_USERPTR: + if (tbuf.length < buf1->bsize) + goto qbuf_exit; + + if ((VIDEOBUF_NEEDS_INIT != buf1->state) + && (buf1->baddr != tbuf.m.userptr)) + vpif_buffer_release(&common->buffer_queue, buf1); + buf1->baddr = tbuf.m.userptr; + break; + + default: + goto qbuf_exit; + } + + local_irq_save(flags); + ret = vpif_buffer_prepare(&common->buffer_queue, buf1, + common->buffer_queue.field); + if (ret < 0) { + local_irq_restore(flags); + goto qbuf_exit; + } + + buf1->state = VIDEOBUF_ACTIVE; + + if (V4L2_MEMORY_USERPTR == common->memory) + addr = buf1->boff; + else + addr = videobuf_to_dma_contig(buf1); + + common->next_frm = buf1; + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); + + local_irq_restore(flags); + list_add_tail(&buf1->stream, &common->buffer_queue.stream); + mutex_unlock(&common->buffer_queue.vb_lock); + return 0; + +qbuf_exit: + mutex_unlock(&common->buffer_queue.vb_lock); + return -EINVAL; +} + +/** + * vpif_dqbuf() - query buffer handler + * @file: file ptr + * @priv: file handle + * @buf: v4l2 buffer structure ptr + */ +static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + vpif_dbg(2, debug, "vpif_dqbuf\n"); + + return videobuf_dqbuf(&common->buffer_queue, buf, + file->f_flags & O_NONBLOCK); +} + +/** + * vpif_streamon() - streamon handler + * @file: file ptr + * @priv: file handle + * @buftype: v4l2 buffer type + */ +static int vpif_streamon(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + + struct vpif_capture_config *config = vpif_dev->platform_data; + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; + struct vpif_params *vpif; + unsigned long addr = 0; + int ret = 0; + + vpif_dbg(2, debug, "vpif_streamon\n"); + + vpif = &ch->vpifparams; + + if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + vpif_dbg(1, debug, "buffer type not supported\n"); + return -EINVAL; + } + + /* If file handle is not allowed IO, return error */ + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_dbg(1, debug, "io not allowed\n"); + return -EACCES; + } + + /* If Streaming is already started, return error */ + if (common->started) { + vpif_dbg(1, debug, "channel->started\n"); + return -EBUSY; + } + + if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && + oth_ch->common[VPIF_VIDEO_INDEX].started && + vpif->std_info.ycmux_mode == 0) || + ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && + (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { + vpif_dbg(1, debug, "other channel is being used\n"); + return -EBUSY; + } + + ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); + if (ret) + return ret; + + /* Enable streamon on the sub device */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, + s_stream, 1); + + if (ret && (ret != -ENOIOCTLCMD)) { + vpif_dbg(1, debug, "stream on failed in subdev\n"); + return ret; + } + + /* Call videobuf_streamon to start streaming in videobuf */ + ret = videobuf_streamon(&common->buffer_queue); + if (ret) { + vpif_dbg(1, debug, "videobuf_streamon\n"); + return ret; + } + + if (mutex_lock_interruptible(&common->lock)) { + ret = -ERESTARTSYS; + goto streamoff_exit; + } + + /* If buffer queue is empty, return error */ + if (list_empty(&common->dma_queue)) { + vpif_dbg(1, debug, "buffer queue is empty\n"); + ret = -EIO; + goto exit; + } + + /* Get the next frame from the buffer queue */ + common->cur_frm = list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + common->next_frm = common->cur_frm; + + /* Remove buffer from the buffer queue */ + list_del(&common->cur_frm->queue); + /* Mark state of the current frame to active */ + common->cur_frm->state = VIDEOBUF_ACTIVE; + /* Initialize field_id and started member */ + ch->field_id = 0; + common->started = 1; + + if (V4L2_MEMORY_USERPTR == common->memory) + addr = common->cur_frm->boff; + else + addr = videobuf_to_dma_contig(common->cur_frm); + + /* Calculate the offset for Y and C data in the buffer */ + vpif_calculate_offsets(ch); + + if ((vpif->std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && + (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || + (!vpif->std_info.frm_fmt && + (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_dbg(1, debug, "conflict in field format and std format\n"); + ret = -EINVAL; + goto exit; + } + + /* configure 1 or 2 channel mode */ + ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + goto exit; + } + + /* Call vpif_set_params function to set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set video params\n"); + goto exit; + } + + common->started = ret; + vpif_config_addr(ch, ret); + + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); + + /** + * Set interrupt for both the fields in VPIF Register enable channel in + * VPIF register + */ + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { + channel0_intr_assert(); + channel0_intr_enable(1); + enable_channel0(1); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (common->started == 2)) { + channel1_intr_assert(); + channel1_intr_enable(1); + enable_channel1(1); + } + channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; + mutex_unlock(&common->lock); + return ret; + +exit: + mutex_unlock(&common->lock); +streamoff_exit: + ret = videobuf_streamoff(&common->buffer_queue); + return ret; +} + +/** + * vpif_streamoff() - streamoff handler + * @file: file ptr + * @priv: file handle + * @buftype: v4l2 buffer type + */ +static int vpif_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret; + + vpif_dbg(2, debug, "vpif_streamoff\n"); + + if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + vpif_dbg(1, debug, "buffer type not supported\n"); + return -EINVAL; + } + + /* If io is allowed for this file handle, return error */ + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_dbg(1, debug, "io not allowed\n"); + return -EACCES; + } + + /* If streaming is not started, return error */ + if (!common->started) { + vpif_dbg(1, debug, "channel->started\n"); + return -EINVAL; + } + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + /* disable channel */ + if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { + enable_channel0(0); + channel0_intr_enable(0); + } else { + enable_channel1(0); + channel1_intr_enable(0); + } + + common->started = 0; + + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, + s_stream, 0); + + if (ret && (ret != -ENOIOCTLCMD)) + vpif_dbg(1, debug, "stream off failed in subdev\n"); + + mutex_unlock(&common->lock); + + return videobuf_streamoff(&common->buffer_queue); +} + +/** + * vpif_map_sub_device_to_input() - Maps sub device to input + * @ch - ptr to channel + * @config - ptr to capture configuration + * @input_index - Given input index from application + * @sub_device_index - index into sd table + * + * lookup the sub device information for a given input index. + * we report all the inputs to application. inputs table also + * has sub device name for the each input + */ +static struct vpif_subdev_info *vpif_map_sub_device_to_input( + struct channel_obj *ch, + struct vpif_capture_config *vpif_cfg, + int input_index, + int *sub_device_index) +{ + struct vpif_capture_chan_config *chan_cfg; + struct vpif_subdev_info *subdev_info = NULL; + const char *subdev_name = NULL; + int i; + + vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); + + chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; + + /** + * search through the inputs to find the sub device supporting + * the input + */ + for (i = 0; i < chan_cfg->input_count; i++) { + /* For each sub device, loop through input */ + if (i == input_index) { + subdev_name = chan_cfg->inputs[i].subdev_name; + break; + } + } + + /* if reached maximum. return null */ + if (i == chan_cfg->input_count || (NULL == subdev_name)) + return subdev_info; + + /* loop through the sub device list to get the sub device info */ + for (i = 0; i < vpif_cfg->subdev_count; i++) { + subdev_info = &vpif_cfg->subdev_info[i]; + if (!strcmp(subdev_info->name, subdev_name)) + break; + } + + if (i == vpif_cfg->subdev_count) + return subdev_info; + + /* check if the sub device is registered */ + if (NULL == vpif_obj.sd[i]) + return NULL; + + *sub_device_index = i; + return subdev_info; +} + +/** + * vpif_querystd() - querystd handler + * @file: file ptr + * @priv: file handle + * @std_id: ptr to std id + * + * This function is called to detect standard at the selected input + */ +static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + vpif_dbg(2, debug, "vpif_querystd\n"); + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + /* Call querystd function of decoder device */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, + querystd, std_id); + if (ret < 0) + vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + + mutex_unlock(&common->lock); + return ret; +} + +/** + * vpif_g_std() - get STD handler + * @file: file ptr + * @priv: file handle + * @std_id: ptr to std id + */ +static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + vpif_dbg(2, debug, "vpif_g_std\n"); + + *std = ch->video.stdid; + return 0; +} + +/** + * vpif_s_std() - set STD handler + * @file: file ptr + * @priv: file handle + * @std_id: ptr to std id + */ +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + vpif_dbg(2, debug, "vpif_s_std\n"); + + if (common->started) { + vpif_err("streaming in progress\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, &fh->prio); + if (0 != ret) + return ret; + + fh->initialized = 1; + + /* Call encoder subdevice function to set the standard */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + ch->video.stdid = *std_id; + + /* Get the information about the standard */ + if (vpif_update_std_info(ch)) { + ret = -EINVAL; + vpif_err("Error getting the standard info\n"); + goto s_std_exit; + } + + /* Configure the default format information */ + vpif_config_format(ch); + + /* set standard in the sub device */ + ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, + s_std, *std_id); + if (ret < 0) + vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + +s_std_exit: + mutex_unlock(&common->lock); + return ret; +} + +/** + * vpif_enum_input() - ENUMINPUT handler + * @file: file ptr + * @priv: file handle + * @input: ptr to input structure + */ +static int vpif_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + + struct vpif_capture_config *config = vpif_dev->platform_data; + struct vpif_capture_chan_config *chan_cfg; + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (input->index >= chan_cfg->input_count) { + vpif_dbg(1, debug, "Invalid input index\n"); + return -EINVAL; + } + + memcpy(input, &chan_cfg->inputs[input->index].input, + sizeof(*input)); + return 0; +} + +/** + * vpif_g_input() - Get INPUT handler + * @file: file ptr + * @priv: file handle + * @index: ptr to input index + */ +static int vpif_g_input(struct file *file, void *priv, unsigned int *index) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + *index = vid_ch->input_idx; + + return 0; +} + +/** + * vpif_s_input() - Set INPUT handler + * @file: file ptr + * @priv: file handle + * @index: input index + */ +static int vpif_s_input(struct file *file, void *priv, unsigned int index) +{ + struct vpif_capture_config *config = vpif_dev->platform_data; + struct vpif_capture_chan_config *chan_cfg; + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + struct vpif_subdev_info *subdev_info; + int ret = 0, sd_index = 0; + u32 input = 0, output = 0; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (common->started) { + vpif_err("Streaming in progress\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, &fh->prio); + if (0 != ret) + return ret; + + fh->initialized = 1; + subdev_info = vpif_map_sub_device_to_input(ch, config, index, + &sd_index); + if (NULL == subdev_info) { + vpif_dbg(1, debug, + "couldn't lookup sub device for the input index\n"); + return -EINVAL; + } + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + /* first setup input path from sub device to vpif */ + if (config->setup_input_path) { + ret = config->setup_input_path(ch->channel_id, + subdev_info->name); + if (ret < 0) { + vpif_dbg(1, debug, "couldn't setup input path for the" + " sub device %s, for input index %d\n", + subdev_info->name, index); + goto exit; + } + } + + if (subdev_info->can_route) { + input = subdev_info->input; + output = subdev_info->output; + ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, + input, output, 0); + if (ret < 0) { + vpif_dbg(1, debug, "Failed to set input\n"); + goto exit; + } + } + vid_ch->input_idx = index; + ch->curr_subdev_info = subdev_info; + ch->curr_sd_index = sd_index; + /* copy interface parameters to vpif */ + ch->vpifparams.iface = subdev_info->vpif_if; + + /* update tvnorms from the sub device input info */ + ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; + +exit: + mutex_unlock(&common->lock); + return ret; +} + +/** + * vpif_enum_fmt_vid_cap() - ENUM_FMT handler + * @file: file ptr + * @priv: file handle + * @index: input index + */ +static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + if (fmt->index != 0) { + vpif_dbg(1, debug, "Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); + fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; + } else { + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); + fmt->pixelformat = V4L2_PIX_FMT_YUV422P; + } + return 0; +} + +/** + * vpif_try_fmt_vid_cap() - TRY_FMT handler + * @file: file ptr + * @priv: file handle + * @fmt: ptr to v4l2 format structure + */ +static int vpif_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + return vpif_check_format(ch, pixfmt, 1); +} + + +/** + * vpif_g_fmt_vid_cap() - Set INPUT handler + * @file: file ptr + * @priv: file handle + * @fmt: ptr to v4l2 format structure + */ +static int vpif_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + /* Check the validity of the buffer type */ + if (common->fmt.type != fmt->type) + return -EINVAL; + + /* Fill in the information about format */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + *fmt = common->fmt; + mutex_unlock(&common->lock); + return 0; +} + +/** + * vpif_s_fmt_vid_cap() - Set FMT handler + * @file: file ptr + * @priv: file handle + * @fmt: ptr to v4l2 format structure + */ +static int vpif_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_pix_format *pixfmt; + int ret = 0; + + vpif_dbg(2, debug, "VIDIOC_S_FMT\n"); + + /* If streaming is started, return error */ + if (common->started) { + vpif_dbg(1, debug, "Streaming is started\n"); + return -EBUSY; + } + + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || + (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + } + + ret = v4l2_prio_check(&ch->prio, &fh->prio); + if (0 != ret) + return ret; + + fh->initialized = 1; + + pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + ret = vpif_check_format(ch, pixfmt, 0); + + if (ret) + return ret; + /* store the format in the channel object */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + common->fmt = *fmt; + mutex_unlock(&common->lock); + + return 0; +} + +/** + * vpif_querycap() - QUERYCAP handler + * @file: file ptr + * @priv: file handle + * @cap: ptr to v4l2_capability structure + */ +static int vpif_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpif_capture_config *config = vpif_dev->platform_data; + + cap->version = VPIF_CAPTURE_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); + strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); + strlcpy(cap->card, config->card_name, sizeof(cap->card)); + + return 0; +} + +/** + * vpif_g_priority() - get priority handler + * @file: file ptr + * @priv: file handle + * @prio: ptr to v4l2_priority structure + */ +static int vpif_g_priority(struct file *file, void *priv, + enum v4l2_priority *prio) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + *prio = v4l2_prio_max(&ch->prio); + + return 0; +} + +/** + * vpif_s_priority() - set priority handler + * @file: file ptr + * @priv: file handle + * @prio: ptr to v4l2_priority structure + */ +static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_prio_change(&ch->prio, &fh->prio, p); +} + +/** + * vpif_cropcap() - cropcap handler + * @file: file ptr + * @priv: file handle + * @crop: ptr to v4l2_cropcap structure + */ +static int vpif_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type) + return -EINVAL; + + crop->bounds.left = 0; + crop->bounds.top = 0; + crop->bounds.height = common->height; + crop->bounds.width = common->width; + crop->defrect = crop->bounds; + return 0; +} + +/* vpif capture ioctl operations */ +static const struct v4l2_ioctl_ops vpif_ioctl_ops = { + .vidioc_querycap = vpif_querycap, + .vidioc_g_priority = vpif_g_priority, + .vidioc_s_priority = vpif_s_priority, + .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap, + .vidioc_enum_input = vpif_enum_input, + .vidioc_s_input = vpif_s_input, + .vidioc_g_input = vpif_g_input, + .vidioc_reqbufs = vpif_reqbufs, + .vidioc_querybuf = vpif_querybuf, + .vidioc_querystd = vpif_querystd, + .vidioc_s_std = vpif_s_std, + .vidioc_g_std = vpif_g_std, + .vidioc_qbuf = vpif_qbuf, + .vidioc_dqbuf = vpif_dqbuf, + .vidioc_streamon = vpif_streamon, + .vidioc_streamoff = vpif_streamoff, + .vidioc_cropcap = vpif_cropcap, +}; + +/* vpif file operations */ +static struct v4l2_file_operations vpif_fops = { + .owner = THIS_MODULE, + .open = vpif_open, + .release = vpif_release, + .ioctl = video_ioctl2, + .mmap = vpif_mmap, + .poll = vpif_poll +}; + +/* vpif video template */ +static struct video_device vpif_video_template = { + .name = "vpif", + .fops = &vpif_fops, + .minor = -1, + .ioctl_ops = &vpif_ioctl_ops, +}; + +/** + * initialize_vpif() - Initialize vpif data structures + * + * Allocate memory for data structures and initialize them + */ +static int initialize_vpif(void) +{ + int err = 0, i, j; + int free_channel_objects_index; + + /* Default number of buffers should be 3 */ + if ((ch0_numbuffers > 0) && + (ch0_numbuffers < config_params.min_numbuffers)) + ch0_numbuffers = config_params.min_numbuffers; + if ((ch1_numbuffers > 0) && + (ch1_numbuffers < config_params.min_numbuffers)) + ch1_numbuffers = config_params.min_numbuffers; + + /* Set buffer size to min buffers size if it is invalid */ + if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]) + ch0_bufsize = + config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]; + if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]) + ch1_bufsize = + config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]; + + config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers; + config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers; + if (ch0_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO] + = ch0_bufsize; + } + if (ch1_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO] + = ch1_bufsize; + } + + /* Allocate memory for six channel objects */ + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + vpif_obj.dev[i] = + kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!vpif_obj.dev[i]) { + free_channel_objects_index = i; + err = -ENOMEM; + goto vpif_init_free_channel_objects; + } + } + return 0; + +vpif_init_free_channel_objects: + for (j = 0; j < free_channel_objects_index; j++) + kfree(vpif_obj.dev[j]); + return err; +} + +/** + * vpif_probe : This function probes the vpif capture driver + * @pdev: platform device pointer + * + * This creates device entries by register itself to the V4L2 driver and + * initializes fields of each channel objects + */ +static __init int vpif_probe(struct platform_device *pdev) +{ + struct vpif_subdev_info *subdevdata; + struct vpif_capture_config *config; + int i, j, k, m, q, err; + struct i2c_adapter *i2c_adap; + struct channel_obj *ch; + struct common_obj *common; + struct video_device *vfd; + struct resource *res; + int subdev_count; + + vpif_dev = &pdev->dev; + + err = initialize_vpif(); + if (err) { + v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); + return err; + } + + k = 0; + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + for (i = res->start; i <= res->end; i++) { + if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, + "DM646x_Capture", + (void *)(&vpif_obj.dev[k]->channel_id))) { + err = -EBUSY; + i--; + goto vpif_int_err; + } + } + k++; + } + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + /* Allocate memory for video device */ + vfd = video_device_alloc(); + if (NULL == vfd) { + for (j = 0; j < i; j++) { + ch = vpif_obj.dev[j]; + video_device_release(ch->video_dev); + } + err = -ENOMEM; + goto vpif_dev_alloc_err; + } + + /* Initialize field of video device */ + *vfd = vpif_video_template; + vfd->v4l2_dev = &vpif_obj.v4l2_dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), + "DM646x_VPIFCapture_DRIVER_V%d.%d.%d", + (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff, + (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff, + (VPIF_CAPTURE_VERSION_CODE) & 0xff); + /* Set video_dev to the video device */ + ch->video_dev = vfd; + } + + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + common = &(ch->common[VPIF_VIDEO_INDEX]); + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 1 : 0)); + if (err) + goto probe_out; + + video_set_drvdata(ch->video_dev, ch); + + } + + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + + subdev_count = config->subdev_count; + vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto probe_out; + } + + err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); + if (err) { + v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); + goto probe_subdev_out; + } + + for (i = 0; i < subdev_count; i++) { + subdevdata = &config->subdev_info[i]; + vpif_obj.sd[i] = + v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, + subdevdata->name, + &subdevdata->board_info, + NULL); + + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", + subdevdata->name); + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver" + " initialized\n"); + + return 0; + +probe_subdev_out: + /* free sub devices memory */ + kfree(vpif_obj.sd); + + j = VPIF_CAPTURE_MAX_DEVICES; +probe_out: + v4l2_device_unregister(&vpif_obj.v4l2_dev); + for (k = 0; k < j; k++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[k]; + /* Unregister video device */ + video_unregister_device(ch->video_dev); + } + +vpif_dev_alloc_err: + k = VPIF_CAPTURE_MAX_DEVICES-1; + res = platform_get_resource(pdev, IORESOURCE_IRQ, k); + i = res->end; + +vpif_int_err: + for (q = k; q >= 0; q--) { + for (m = i; m >= (int)res->start; m--) + free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); + if (res) + i = res->end; + } + return err; +} + +/** + * vpif_remove() - driver remove handler + * @device: ptr to platform device structure + * + * The vidoe device is unregistered + */ +static int vpif_remove(struct platform_device *device) +{ + int i; + struct channel_obj *ch; + + v4l2_device_unregister(&vpif_obj.v4l2_dev); + + /* un-register device */ + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + /* Unregister video device */ + video_unregister_device(ch->video_dev); + } + return 0; +} + +/** + * vpif_suspend: vpif device suspend + * + * TODO: Add suspend code here + */ +static int +vpif_suspend(struct device *dev) +{ + return -1; +} + +/** + * vpif_resume: vpif device suspend + * + * TODO: Add resume code here + */ +static int +vpif_resume(struct device *dev) +{ + return -1; +} + +static const struct dev_pm_ops vpif_dev_pm_ops = { + .suspend = vpif_suspend, + .resume = vpif_resume, +}; + +static struct platform_driver vpif_driver = { + .driver = { + .name = "vpif_capture", + .owner = THIS_MODULE, + .pm = &vpif_dev_pm_ops, + }, + .probe = vpif_probe, + .remove = vpif_remove, +}; + +/** + * vpif_init: initialize the vpif driver + * + * This function registers device and driver to the kernel, requests irq + * handler and allocates memory + * for channel objects + */ +static __init int vpif_init(void) +{ + return platform_driver_register(&vpif_driver); +} + +/** + * vpif_cleanup : This function clean up the vpif capture resources + * + * This will un-registers device and driver to the kernel, frees + * requested irq handler and de-allocates memory allocated for channel + * objects. + */ +static void vpif_cleanup(void) +{ + struct platform_device *pdev; + struct resource *res; + int irq_num; + int i = 0; + + pdev = container_of(vpif_dev, struct platform_device, dev); + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, + (void *)(&vpif_obj.dev[i]->channel_id)); + i++; + } + + platform_driver_unregister(&vpif_driver); + + kfree(vpif_obj.sd); + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + +/* Function for module initialization and cleanup */ +module_init(vpif_init); +module_exit(vpif_cleanup); diff --git a/drivers/media/video/ti-media/vpif_capture.h b/drivers/media/video/ti-media/vpif_capture.h new file mode 100644 index 0000000..4e12ec8 --- /dev/null +++ b/drivers/media/video/ti-media/vpif_capture.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 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 VPIF_CAPTURE_H +#define VPIF_CAPTURE_H + +#ifdef __KERNEL__ + +/* Header files */ +#include +#include +#include +#include +#include +#include +#include + +#include "vpif.h" + +/* Macros */ +#define VPIF_MAJOR_RELEASE 0 +#define VPIF_MINOR_RELEASE 0 +#define VPIF_BUILD 1 +#define VPIF_CAPTURE_VERSION_CODE ((VPIF_MAJOR_RELEASE << 16) | \ + (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) + +#define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ + (V4L2_FIELD_NONE == field)) || \ + (((V4L2_FIELD_INTERLACED == field) || \ + (V4L2_FIELD_SEQ_TB == field)) || \ + (V4L2_FIELD_SEQ_BT == field))) + +#define VPIF_CAPTURE_MAX_DEVICES 2 +#define VPIF_VIDEO_INDEX 0 +#define VPIF_NUMBER_OF_OBJECTS 1 + +/* Enumerated data type to give id to each device per channel */ +enum vpif_channel_id { + VPIF_CHANNEL0_VIDEO = 0, + VPIF_CHANNEL1_VIDEO, +}; + +struct video_obj { + enum v4l2_field buf_field; + /* Currently selected or default standard */ + v4l2_std_id stdid; + /* This is to track the last input that is passed to application */ + u32 input_idx; +}; + +struct common_obj { + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *cur_frm; + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *next_frm; + /* + * 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; + /* lock used to access this structure */ + struct mutex lock; + /* number of users performing IO */ + u32 io_usrs; + /* Indicates whether streaming started */ + u8 started; + /* Function pointer to set the addresses */ + void (*set_addr) (unsigned long, unsigned long, unsigned long, + unsigned long); + /* offset where Y top starts from the starting of the buffer */ + u32 ytop_off; + /* offset where Y bottom starts from the starting of the buffer */ + u32 ybtm_off; + /* offset where C top starts from the starting of the buffer */ + u32 ctop_off; + /* offset where C bottom starts from the starting of the buffer */ + u32 cbtm_off; + /* Indicates width of the image data */ + u32 width; + /* Indicates height of the image data */ + u32 height; +}; + +struct channel_obj { + /* 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 */ + int 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 vpif_channel_id channel_id; + /* index into sd table */ + int curr_sd_index; + /* ptr to current sub device information */ + struct vpif_subdev_info *curr_subdev_info; + /* vpif configuration params */ + struct vpif_params vpifparams; + /* common object array */ + struct common_obj common[VPIF_NUMBER_OF_OBJECTS]; + /* video object */ + struct video_obj video; +}; + +/* File handle structure */ +struct vpif_fh { + /* pointer to channel object for opened device */ + struct channel_obj *channel; + /* Indicates whether this file handle is doing IO */ + u8 io_allowed[VPIF_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; +}; + +struct vpif_device { + struct v4l2_device v4l2_dev; + struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS]; + struct v4l2_subdev **sd; +}; + +struct vpif_config_params { + u8 min_numbuffers; + u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS]; + s8 device_type; + u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; + u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; + u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; + u8 max_device_type; +}; +/* Struct which keeps track of the line numbers for the sliced vbi service */ +struct vpif_service_line { + u16 service_id; + u16 service_line[2]; +}; +#endif /* End of __KERNEL__ */ +#endif /* VPIF_CAPTURE_H */ diff --git a/drivers/media/video/ti-media/vpif_display.c b/drivers/media/video/ti-media/vpif_display.c new file mode 100644 index 0000000..b2dce78 --- /dev/null +++ b/drivers/media/video/ti-media/vpif_display.c @@ -0,0 +1,1654 @@ +/* + * vpif-display - VPIF display driver + * Display driver for TI DaVinci VPIF + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "vpif_display.h" +#include "vpif.h" + +MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); +MODULE_LICENSE("GPL"); + +#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) + +#define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) +#define vpif_dbg(level, debug, fmt, arg...) \ + v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) + +static int debug = 1; +static u32 ch2_numbuffers = 3; +static u32 ch3_numbuffers = 3; +static u32 ch2_bufsize = 1920 * 1080 * 2; +static u32 ch3_bufsize = 720 * 576 * 2; + +module_param(debug, int, 0644); +module_param(ch2_numbuffers, uint, S_IRUGO); +module_param(ch3_numbuffers, uint, S_IRUGO); +module_param(ch2_bufsize, uint, S_IRUGO); +module_param(ch3_bufsize, uint, S_IRUGO); + +MODULE_PARM_DESC(debug, "Debug level 0-1"); +MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)"); +MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)"); +MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)"); +MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)"); + +static struct vpif_config_params config_params = { + .min_numbuffers = 3, + .numbuffers[0] = 3, + .numbuffers[1] = 3, + .min_bufsize[0] = 720 * 480 * 2, + .min_bufsize[1] = 720 * 480 * 2, + .channel_bufsize[0] = 1920 * 1080 * 2, + .channel_bufsize[1] = 720 * 576 * 2, +}; + +static struct vpif_device vpif_obj = { {NULL} }; +static struct device *vpif_dev; + +static const struct vpif_channel_config_params ch_params[] = { + { + "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266, + 286, 525, 525, 0, 1, 0, V4L2_STD_525_60, + }, + { + "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313, + 336, 624, 625, 0, 1, 0, V4L2_STD_625_50, + }, +}; + +/* + * vpif_uservirt_to_phys: This function is used to convert user + * space virtual address to physical address. + */ +static u32 vpif_uservirt_to_phys(u32 virtp) +{ + struct mm_struct *mm = current->mm; + unsigned long physp = 0; + struct vm_area_struct *vma; + + vma = find_vma(mm, virtp); + + /* For kernel direct-mapped memory, take the easy way */ + if (virtp >= PAGE_OFFSET) { + physp = virt_to_phys((void *)virtp); + } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { + /* this will catch, kernel-allocated, mmaped-to-usermode addr */ + physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); + } else { + /* otherwise, use get_user_pages() for general userland pages */ + int res, nr_pages = 1; + struct page *pages; + down_read(¤t->mm->mmap_sem); + + res = get_user_pages(current, current->mm, + virtp, nr_pages, 1, 0, &pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (res == nr_pages) { + physp = __pa(page_address(&pages[0]) + + (virtp & ~PAGE_MASK)); + } else { + vpif_err("get_user_pages failed\n"); + return 0; + } + } + + return physp; +} + +/* + * buffer_prepare: This is the callback function called from videobuf_qbuf() + * function the buffer is prepared and user space virtual address is converted + * into physical address + */ +static int vpif_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct vpif_fh *fh = q->priv_data; + struct common_obj *common; + unsigned long addr; + + common = &fh->channel->common[VPIF_VIDEO_INDEX]; + if (VIDEOBUF_NEEDS_INIT == vb->state) { + vb->width = common->width; + vb->height = common->height; + vb->size = vb->width * vb->height; + vb->field = field; + } + vb->state = VIDEOBUF_PREPARED; + + /* if user pointer memory mechanism is used, get the physical + * address of the buffer */ + if (V4L2_MEMORY_USERPTR == common->memory) { + if (!vb->baddr) { + vpif_err("buffer_address is 0\n"); + return -EINVAL; + } + + vb->boff = vpif_uservirt_to_phys(vb->baddr); + if (!ISALIGNED(vb->boff)) + goto buf_align_exit; + } + + addr = vb->boff; + if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { + if (!ISALIGNED(addr + common->ytop_off) || + !ISALIGNED(addr + common->ybtm_off) || + !ISALIGNED(addr + common->ctop_off) || + !ISALIGNED(addr + common->cbtm_off)) + goto buf_align_exit; + } + return 0; + +buf_align_exit: + vpif_err("buffer offset not aligned to 8 bytes\n"); + return -EINVAL; +} + +/* + * vpif_buffer_setup: This function allocates memory for the buffers + */ +static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (V4L2_MEMORY_MMAP != common->memory) + return 0; + + *size = config_params.channel_bufsize[ch->channel_id]; + if (*count < config_params.min_numbuffers) + *count = config_params.min_numbuffers; + + return 0; +} + +/* + * vpif_buffer_queue: This function adds the buffer to DMA queue + */ +static void vpif_buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct vpif_fh *fh = q->priv_data; + struct common_obj *common; + + common = &fh->channel->common[VPIF_VIDEO_INDEX]; + + /* add the buffer to the DMA queue */ + list_add_tail(&vb->queue, &common->dma_queue); + vb->state = VIDEOBUF_QUEUED; +} + +/* + * vpif_buffer_release: This function is called from the videobuf layer to + * free memory allocated to the buffers + */ +static void vpif_buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct vpif_fh *fh = q->priv_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + unsigned int buf_size = 0; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + videobuf_dma_contig_free(q, vb); + vb->state = VIDEOBUF_NEEDS_INIT; + + if (V4L2_MEMORY_MMAP != common->memory) + return; + + buf_size = config_params.channel_bufsize[ch->channel_id]; +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = vpif_buffer_setup, + .buf_prepare = vpif_buffer_prepare, + .buf_queue = vpif_buffer_queue, + .buf_release = vpif_buffer_release, +}; +static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; + +static void process_progressive_mode(struct common_obj *common) +{ + unsigned long addr = 0; + + /* Get the next buffer from buffer queue */ + common->next_frm = list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + /* Remove that buffer from the buffer queue */ + list_del(&common->next_frm->queue); + /* Mark status of the buffer as active */ + common->next_frm->state = VIDEOBUF_ACTIVE; + + /* Set top and bottom field addrs in VPIF registers */ + addr = videobuf_to_dma_contig(common->next_frm); + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); +} + +static void process_interlaced_mode(int fid, struct common_obj *common) +{ + /* device field id and local field id are in sync */ + /* If this is even field */ + if (0 == fid) { + if (common->cur_frm == common->next_frm) + return; + + /* one frame is displayed If next frame is + * available, release cur_frm and move on */ + /* Copy frame display time */ + do_gettimeofday(&common->cur_frm->ts); + /* Change status of the cur_frm */ + common->cur_frm->state = VIDEOBUF_DONE; + /* unlock semaphore on cur_frm */ + wake_up_interruptible(&common->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + common->cur_frm = common->next_frm; + + } else if (1 == fid) { /* odd field */ + if (list_empty(&common->dma_queue) + || (common->cur_frm != common->next_frm)) { + return; + } + /* one field is displayed configure the next + * frame if it is available else hold on current + * frame */ + /* Get next from the buffer queue */ + process_progressive_mode(common); + + } +} + +/* + * vpif_channel_isr: It changes status of the displayed buffer, takes next + * buffer from the queue and sets its address in VPIF registers + */ +static irqreturn_t vpif_channel_isr(int irq, void *dev_id) +{ + struct vpif_device *dev = &vpif_obj; + struct channel_obj *ch; + struct common_obj *common; + enum v4l2_field field; + int fid = -1, i; + int channel_id = 0; + + channel_id = *(int *)(dev_id); + ch = dev->dev[channel_id]; + field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; + for (i = 0; i < VPIF_NUMOBJECTS; i++) { + common = &ch->common[i]; + /* If streaming is started in this channel */ + if (0 == common->started) + continue; + + if (1 == ch->vpifparams.std_info.frm_fmt) { + if (list_empty(&common->dma_queue)) + continue; + + /* Progressive mode */ + if (!channel_first_int[i][channel_id]) { + /* Mark status of the cur_frm to + * done and unlock semaphore on it */ + do_gettimeofday(&common->cur_frm->ts); + common->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&common->cur_frm->done); + /* Make cur_frm pointing to next_frm */ + common->cur_frm = common->next_frm; + } + + channel_first_int[i][channel_id] = 0; + process_progressive_mode(common); + } else { + /* Interlaced mode */ + /* If it is first interrupt, ignore it */ + + if (channel_first_int[i][channel_id]) { + channel_first_int[i][channel_id] = 0; + continue; + } + + if (0 == i) { + ch->field_id ^= 1; + /* Get field id from VPIF registers */ + fid = vpif_channel_getfid(ch->channel_id + 2); + /* If fid does not match with stored field id */ + if (fid != ch->field_id) { + /* Make them in sync */ + if (0 == fid) + ch->field_id = fid; + + return IRQ_HANDLED; + } + } + process_interlaced_mode(fid, common); + } + } + + return IRQ_HANDLED; +} + +static int vpif_get_std_info(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct video_obj *vid_ch = &ch->video; + struct vpif_params *vpifparams = &ch->vpifparams; + struct vpif_channel_config_params *std_info = &vpifparams->std_info; + const struct vpif_channel_config_params *config; + + int index; + + std_info->stdid = vid_ch->stdid; + if (!std_info->stdid) + return -1; + + for (index = 0; index < ARRAY_SIZE(ch_params); index++) { + config = &ch_params[index]; + if (config->stdid & std_info->stdid) { + memcpy(std_info, config, sizeof(*config)); + break; + } + } + + if (index == ARRAY_SIZE(ch_params)) + return -1; + + common->fmt.fmt.pix.width = std_info->width; + common->fmt.fmt.pix.height = std_info->height; + vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", + common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); + + /* Set height and width paramateres */ + ch->common[VPIF_VIDEO_INDEX].height = std_info->height; + ch->common[VPIF_VIDEO_INDEX].width = std_info->width; + + return 0; +} + +/* + * vpif_calculate_offsets: This function calculates buffers offset for Y and C + * in the top and bottom field + */ +static void vpif_calculate_offsets(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_params *vpifparams = &ch->vpifparams; + enum v4l2_field field = common->fmt.fmt.pix.field; + struct video_obj *vid_ch = &ch->video; + unsigned int hpitch, vpitch, sizeimage; + + if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { + if (ch->vpifparams.std_info.frm_fmt) + vid_ch->buf_field = V4L2_FIELD_NONE; + else + vid_ch->buf_field = V4L2_FIELD_INTERLACED; + } else { + vid_ch->buf_field = common->fmt.fmt.pix.field; + } + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = common->fmt.fmt.pix.sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + hpitch = common->fmt.fmt.pix.bytesperline; + vpitch = sizeimage / (hpitch * 2); + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { + common->ytop_off = 0; + common->ybtm_off = hpitch; + common->ctop_off = sizeimage / 2; + common->cbtm_off = sizeimage / 2 + hpitch; + } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { + common->ytop_off = 0; + common->ybtm_off = sizeimage / 4; + common->ctop_off = sizeimage / 2; + common->cbtm_off = common->ctop_off + sizeimage / 4; + } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { + common->ybtm_off = 0; + common->ytop_off = sizeimage / 4; + common->cbtm_off = sizeimage / 2; + common->ctop_off = common->cbtm_off + sizeimage / 4; + } + + if ((V4L2_FIELD_NONE == vid_ch->buf_field) || + (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { + vpifparams->video_params.storage_mode = 1; + } else { + vpifparams->video_params.storage_mode = 0; + } + + if (ch->vpifparams.std_info.frm_fmt == 1) { + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + } else { + if ((field == V4L2_FIELD_ANY) || + (field == V4L2_FIELD_INTERLACED)) + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline * 2; + else + vpifparams->video_params.hpitch = + common->fmt.fmt.pix.bytesperline; + } + + ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid; +} + +static void vpif_config_format(struct channel_obj *ch) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + common->fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (config_params.numbuffers[ch->channel_id] == 0) + common->memory = V4L2_MEMORY_USERPTR; + else + common->memory = V4L2_MEMORY_MMAP; + + common->fmt.fmt.pix.sizeimage = + config_params.channel_bufsize[ch->channel_id]; + common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; + common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +} + +static int vpif_check_format(struct channel_obj *ch, + struct v4l2_pix_format *pixfmt) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + enum v4l2_field field = pixfmt->field; + u32 sizeimage, hpitch, vpitch; + + if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) + goto invalid_fmt_exit; + + if (!(VPIF_VALID_FIELD(field))) + goto invalid_fmt_exit; + + if (pixfmt->bytesperline <= 0) + goto invalid_pitch_exit; + + if (V4L2_MEMORY_USERPTR == common->memory) + sizeimage = pixfmt->sizeimage; + else + sizeimage = config_params.channel_bufsize[ch->channel_id]; + + if (vpif_get_std_info(ch)) { + vpif_err("Error getting the standard info\n"); + return -EINVAL; + } + + hpitch = pixfmt->bytesperline; + vpitch = sizeimage / (hpitch * 2); + + /* Check for valid value of pitch */ + if ((hpitch < ch->vpifparams.std_info.width) || + (vpitch < ch->vpifparams.std_info.height)) + goto invalid_pitch_exit; + + /* Check for 8 byte alignment */ + if (!ISALIGNED(hpitch)) { + vpif_err("invalid pitch alignment\n"); + return -EINVAL; + } + pixfmt->width = common->fmt.fmt.pix.width; + pixfmt->height = common->fmt.fmt.pix.height; + + return 0; + +invalid_fmt_exit: + vpif_err("invalid field format\n"); + return -EINVAL; + +invalid_pitch_exit: + vpif_err("invalid pitch\n"); + return -EINVAL; +} + +static void vpif_config_addr(struct channel_obj *ch, int muxmode) +{ + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { + common->set_addr = ch3_set_videobuf_addr; + } else { + if (2 == muxmode) + common->set_addr = ch2_set_videobuf_addr_yc_nmux; + else + common->set_addr = ch2_set_videobuf_addr; + } +} + +/* + * vpif_mmap: It is used to map kernel space buffers into user spaces + */ +static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) +{ + struct vpif_fh *fh = filep->private_data; + struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX]; + + return videobuf_mmap_mapper(&common->buffer_queue, vma); +} + +/* + * vpif_poll: It is used for select/poll system call + */ +static unsigned int vpif_poll(struct file *filep, poll_table *wait) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (common->started) + return videobuf_poll_stream(filep, &common->buffer_queue, wait); + + return 0; +} + +/* + * vpif_open: It creates object of file handle structure and stores it in + * private_data member of filepointer + */ +static int vpif_open(struct file *filep) +{ + struct video_device *vdev = video_devdata(filep); + struct channel_obj *ch = NULL; + struct vpif_fh *fh = NULL; + + ch = video_get_drvdata(vdev); + /* Allocate memory for the file handle object */ + fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL); + if (fh == NULL) { + vpif_err("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 = ch; + fh->initialized = 0; + if (!ch->initialized) { + fh->initialized = 1; + ch->initialized = 1; + memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); + } + + /* Increment channel usrs counter */ + atomic_inc(&ch->usrs); + /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */ + fh->io_allowed[VPIF_VIDEO_INDEX] = 0; + /* Initialize priority of this instance to default priority */ + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&ch->prio, &fh->prio); + + return 0; +} + +/* + * vpif_release: This function deletes buffer queue, frees the buffers and + * the vpif file handle + */ +static int vpif_release(struct file *filep) +{ + struct vpif_fh *fh = filep->private_data; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + /* if this instance is doing IO */ + if (fh->io_allowed[VPIF_VIDEO_INDEX]) { + /* Reset io_usrs member of channel object */ + common->io_usrs = 0; + /* Disable channel */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + enable_channel2(0); + channel2_intr_enable(0); + } + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel3(0); + channel3_intr_enable(0); + } + common->started = 0; + /* Free buffers allocated */ + videobuf_queue_cancel(&common->buffer_queue); + videobuf_mmap_free(&common->buffer_queue); + common->numbuffers = + config_params.numbuffers[ch->channel_id]; + } + + mutex_unlock(&common->lock); + + /* Decrement channel usrs counter */ + atomic_dec(&ch->usrs); + /* If this file handle has initialize encoder device, reset it */ + if (fh->initialized) + ch->initialized = 0; + + /* Close the priority */ + v4l2_prio_close(&ch->prio, &fh->prio); + filep->private_data = NULL; + fh->initialized = 0; + kfree(fh); + + return 0; +} + +/* functions implementing ioctls */ + +static int vpif_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpif_display_config *config = vpif_dev->platform_data; + + cap->version = VPIF_DISPLAY_VERSION_CODE; + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); + strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); + strlcpy(cap->card, config->card_name, sizeof(cap->card)); + + return 0; +} + +static int vpif_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index != 0) { + vpif_err("Invalid format index\n"); + return -EINVAL; + } + + /* Fill in the information about format */ + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); + fmt->pixelformat = V4L2_PIX_FMT_YUV422P; + + return 0; +} + +static int vpif_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + /* Check the validity of the buffer type */ + if (common->fmt.type != fmt->type) + return -EINVAL; + + /* Fill in the information about format */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + if (vpif_get_std_info(ch)) { + vpif_err("Error getting the standard info\n"); + return -EINVAL; + } + + *fmt = common->fmt; + mutex_unlock(&common->lock); + return 0; +} + +static int vpif_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct v4l2_pix_format *pixfmt; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) + || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_dbg(1, debug, "Channel Busy\n"); + return -EBUSY; + } + + /* Check for the priority */ + ret = v4l2_prio_check(&ch->prio, &fh->prio); + if (0 != ret) + return ret; + fh->initialized = 1; + } + + if (common->started) { + vpif_dbg(1, debug, "Streaming in progress\n"); + return -EBUSY; + } + + pixfmt = &fmt->fmt.pix; + /* Check for valid field format */ + ret = vpif_check_format(ch, pixfmt); + if (ret) + return ret; + + /* store the pix format in the channel object */ + common->fmt.fmt.pix = *pixfmt; + /* store the format in the channel object */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + common->fmt = *fmt; + mutex_unlock(&common->lock); + + return 0; +} + +static int vpif_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + int ret = 0; + + ret = vpif_check_format(ch, pixfmt); + if (ret) { + *pixfmt = common->fmt.fmt.pix; + pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2; + } + + return ret; +} + +static int vpif_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbuf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common; + enum v4l2_field field; + u8 index = 0; + int ret = 0; + + /* This file handle has not initialized the channel, + It is not allowed to do settings */ + if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) + || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { + if (!fh->initialized) { + vpif_err("Channel Busy\n"); + return -EBUSY; + } + } + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type) + return -EINVAL; + + index = VPIF_VIDEO_INDEX; + + common = &ch->common[index]; + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + if (common->fmt.type != reqbuf->type) { + ret = -EINVAL; + goto reqbuf_exit; + } + + if (0 != common->io_usrs) { + ret = -EBUSY; + goto reqbuf_exit; + } + + if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) + field = V4L2_FIELD_INTERLACED; + else + field = common->fmt.fmt.pix.field; + } else { + field = V4L2_VBI_INTERLACED; + } + + /* Initialize videobuf queue as per the buffer type */ + videobuf_queue_dma_contig_init(&common->buffer_queue, + &video_qops, NULL, + &common->irqlock, + reqbuf->type, field, + sizeof(struct videobuf_buffer), fh); + + /* Set io allowed member of file handle to TRUE */ + fh->io_allowed[index] = 1; + /* Increment io usrs member of channel object to 1 */ + common->io_usrs = 1; + /* Store type of memory requested in channel object */ + common->memory = reqbuf->memory; + INIT_LIST_HEAD(&common->dma_queue); + + /* Allocate buffers */ + ret = videobuf_reqbufs(&common->buffer_queue, reqbuf); + +reqbuf_exit: + mutex_unlock(&common->lock); + return ret; +} + +static int vpif_querybuf(struct file *file, void *priv, + struct v4l2_buffer *tbuf) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (common->fmt.type != tbuf->type) + return -EINVAL; + + return videobuf_querybuf(&common->buffer_queue, tbuf); +} + +static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct v4l2_buffer tbuf = *buf; + struct videobuf_buffer *buf1; + unsigned long addr = 0; + unsigned long flags; + int ret = 0; + + if (common->fmt.type != tbuf.type) + return -EINVAL; + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh->io_allowed\n"); + return -EACCES; + } + + if (!(list_empty(&common->dma_queue)) || + (common->cur_frm != common->next_frm) || + !(common->started) || + (common->started && (0 == ch->field_id))) + return videobuf_qbuf(&common->buffer_queue, buf); + + /* bufferqueue is empty store buffer address in VPIF registers */ + mutex_lock(&common->buffer_queue.vb_lock); + buf1 = common->buffer_queue.bufs[tbuf.index]; + if (buf1->memory != tbuf.memory) { + vpif_err("invalid buffer type\n"); + goto qbuf_exit; + } + + if ((buf1->state == VIDEOBUF_QUEUED) || + (buf1->state == VIDEOBUF_ACTIVE)) { + vpif_err("invalid state\n"); + goto qbuf_exit; + } + + switch (buf1->memory) { + case V4L2_MEMORY_MMAP: + if (buf1->baddr == 0) + goto qbuf_exit; + break; + + case V4L2_MEMORY_USERPTR: + if (tbuf.length < buf1->bsize) + goto qbuf_exit; + + if ((VIDEOBUF_NEEDS_INIT != buf1->state) + && (buf1->baddr != tbuf.m.userptr)) + vpif_buffer_release(&common->buffer_queue, buf1); + buf1->baddr = tbuf.m.userptr; + break; + + default: + goto qbuf_exit; + } + + local_irq_save(flags); + ret = vpif_buffer_prepare(&common->buffer_queue, buf1, + common->buffer_queue.field); + if (ret < 0) { + local_irq_restore(flags); + goto qbuf_exit; + } + + buf1->state = VIDEOBUF_ACTIVE; + addr = buf1->boff; + common->next_frm = buf1; + if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { + common->set_addr((addr + common->ytop_off), + (addr + common->ybtm_off), + (addr + common->ctop_off), + (addr + common->cbtm_off)); + } + + local_irq_restore(flags); + list_add_tail(&buf1->stream, &common->buffer_queue.stream); + mutex_unlock(&common->buffer_queue.vb_lock); + return 0; + +qbuf_exit: + mutex_unlock(&common->buffer_queue.vb_lock); + return -EINVAL; +} + +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if (!(*std_id & DM646X_V4L2_STD)) + return -EINVAL; + + if (common->started) { + vpif_err("streaming in progress\n"); + return -EBUSY; + } + + /* Call encoder subdevice function to set the standard */ + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + ch->video.stdid = *std_id; + /* Get the information about the standard */ + if (vpif_get_std_info(ch)) { + vpif_err("Error getting the standard info\n"); + return -EINVAL; + } + + if ((ch->vpifparams.std_info.width * + ch->vpifparams.std_info.height * 2) > + config_params.channel_bufsize[ch->channel_id]) { + vpif_err("invalid std for this size\n"); + ret = -EINVAL; + goto s_std_exit; + } + + common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; + /* Configure the default format information */ + vpif_config_format(ch); + + ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, + s_std_output, *std_id); + if (ret < 0) { + vpif_err("Failed to set output standard\n"); + goto s_std_exit; + } + + ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, + s_std, *std_id); + if (ret < 0) + vpif_err("Failed to set standard for sub devices\n"); + +s_std_exit: + mutex_unlock(&common->lock); + return ret; +} + +static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + *std = ch->video.stdid; + return 0; +} + +static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + return videobuf_dqbuf(&common->buffer_queue, p, + (file->f_flags & O_NONBLOCK)); +} + +static int vpif_streamon(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; + struct vpif_params *vpif = &ch->vpifparams; + struct vpif_display_config *vpif_config_data = + vpif_dev->platform_data; + unsigned long addr = 0; + int ret = 0; + + if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + vpif_err("buffer type not supported\n"); + return -EINVAL; + } + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh->io_allowed\n"); + return -EACCES; + } + + /* If Streaming is already started, return error */ + if (common->started) { + vpif_err("channel->started\n"); + return -EBUSY; + } + + if ((ch->channel_id == VPIF_CHANNEL2_VIDEO + && oth_ch->common[VPIF_VIDEO_INDEX].started && + ch->vpifparams.std_info.ycmux_mode == 0) + || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) + && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { + vpif_err("other channel is using\n"); + return -EBUSY; + } + + ret = vpif_check_format(ch, &common->fmt.fmt.pix); + if (ret < 0) + return ret; + + /* Call videobuf_streamon to start streaming in videobuf */ + ret = videobuf_streamon(&common->buffer_queue); + if (ret < 0) { + vpif_err("videobuf_streamon\n"); + return ret; + } + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + /* If buffer queue is empty, return error */ + if (list_empty(&common->dma_queue)) { + vpif_err("buffer queue is empty\n"); + ret = -EIO; + goto streamon_exit; + } + + /* Get the next frame from the buffer queue */ + common->next_frm = common->cur_frm = + list_entry(common->dma_queue.next, + struct videobuf_buffer, queue); + + list_del(&common->cur_frm->queue); + /* Mark state of the current frame to active */ + common->cur_frm->state = VIDEOBUF_ACTIVE; + + /* Initialize field_id and started member */ + ch->field_id = 0; + common->started = 1; + if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + addr = common->cur_frm->boff; + /* Calculate the offset for Y and C data in the buffer */ + vpif_calculate_offsets(ch); + + if ((ch->vpifparams.std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) + && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) + || (!ch->vpifparams.std_info.frm_fmt + && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_err("conflict in field format and std format\n"); + ret = -EINVAL; + goto streamon_exit; + } + + /* clock settings */ + ret = + vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, + ch->vpifparams.std_info.hd_sd); + if (ret < 0) { + vpif_err("can't set clock\n"); + goto streamon_exit; + } + + /* set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id + 2); + if (ret < 0) + goto streamon_exit; + + common->started = ret; + vpif_config_addr(ch, ret); + common->set_addr((addr + common->ytop_off), + (addr + common->ybtm_off), + (addr + common->ctop_off), + (addr + common->cbtm_off)); + + /* Set interrupt for both the fields in VPIF + Register enable channel in VPIF register */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + channel2_intr_assert(); + channel2_intr_enable(1); + enable_channel2(1); + } + + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) + || (common->started == 2)) { + channel3_intr_assert(); + channel3_intr_enable(1); + enable_channel3(1); + } + channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; + } + +streamon_exit: + mutex_unlock(&common->lock); + return ret; +} + +static int vpif_streamoff(struct file *file, void *priv, + enum v4l2_buf_type buftype) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + + if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + vpif_err("buffer type not supported\n"); + return -EINVAL; + } + + if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { + vpif_err("fh->io_allowed\n"); + return -EACCES; + } + + if (!common->started) { + vpif_err("channel->started\n"); + return -EINVAL; + } + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + /* disable channel */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + enable_channel2(0); + channel2_intr_enable(0); + } + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || + (2 == common->started)) { + enable_channel3(0); + channel3_intr_enable(0); + } + } + + common->started = 0; + mutex_unlock(&common->lock); + + return videobuf_streamoff(&common->buffer_queue); +} + +static int vpif_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type) + return -EINVAL; + + crop->bounds.left = crop->bounds.top = 0; + crop->defrect.left = crop->defrect.top = 0; + crop->defrect.height = crop->bounds.height = common->height; + crop->defrect.width = crop->bounds.width = common->width; + + return 0; +} + +static int vpif_enum_output(struct file *file, void *fh, + struct v4l2_output *output) +{ + + struct vpif_display_config *config = vpif_dev->platform_data; + + if (output->index >= config->output_count) { + vpif_dbg(1, debug, "Invalid output index\n"); + return -EINVAL; + } + + strcpy(output->name, config->output[output->index]); + output->type = V4L2_OUTPUT_TYPE_ANALOG; + output->std = DM646X_V4L2_STD; + + return 0; +} + +static int vpif_s_output(struct file *file, void *priv, unsigned int i) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + int ret = 0; + + if (mutex_lock_interruptible(&common->lock)) + return -ERESTARTSYS; + + if (common->started) { + vpif_err("Streaming in progress\n"); + ret = -EBUSY; + goto s_output_exit; + } + + ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, + s_routing, 0, i, 0); + + if (ret < 0) + vpif_err("Failed to set output standard\n"); + + vid_ch->output_id = i; + +s_output_exit: + mutex_unlock(&common->lock); + return ret; +} + +static int vpif_g_output(struct file *file, void *priv, unsigned int *i) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + struct video_obj *vid_ch = &ch->video; + + *i = vid_ch->output_id; + + return 0; +} + +static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + *p = v4l2_prio_max(&ch->prio); + + return 0; +} + +static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) +{ + struct vpif_fh *fh = priv; + struct channel_obj *ch = fh->channel; + + return v4l2_prio_change(&ch->prio, &fh->prio, p); +} + +/* vpif display ioctl operations */ +static const struct v4l2_ioctl_ops vpif_ioctl_ops = { + .vidioc_querycap = vpif_querycap, + .vidioc_g_priority = vpif_g_priority, + .vidioc_s_priority = vpif_s_priority, + .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out, + .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out, + .vidioc_reqbufs = vpif_reqbufs, + .vidioc_querybuf = vpif_querybuf, + .vidioc_qbuf = vpif_qbuf, + .vidioc_dqbuf = vpif_dqbuf, + .vidioc_streamon = vpif_streamon, + .vidioc_streamoff = vpif_streamoff, + .vidioc_s_std = vpif_s_std, + .vidioc_g_std = vpif_g_std, + .vidioc_enum_output = vpif_enum_output, + .vidioc_s_output = vpif_s_output, + .vidioc_g_output = vpif_g_output, + .vidioc_cropcap = vpif_cropcap, +}; + +static const struct v4l2_file_operations vpif_fops = { + .owner = THIS_MODULE, + .open = vpif_open, + .release = vpif_release, + .ioctl = video_ioctl2, + .mmap = vpif_mmap, + .poll = vpif_poll +}; + +static struct video_device vpif_video_template = { + .name = "vpif", + .fops = &vpif_fops, + .ioctl_ops = &vpif_ioctl_ops, + .tvnorms = DM646X_V4L2_STD, + .current_norm = V4L2_STD_625_50, + +}; + +/*Configure the channels, buffer sizei, request irq */ +static int initialize_vpif(void) +{ + int free_channel_objects_index; + int free_buffer_channel_index; + int free_buffer_index; + int err = 0, i, j; + + /* Default number of buffers should be 3 */ + if ((ch2_numbuffers > 0) && + (ch2_numbuffers < config_params.min_numbuffers)) + ch2_numbuffers = config_params.min_numbuffers; + if ((ch3_numbuffers > 0) && + (ch3_numbuffers < config_params.min_numbuffers)) + ch3_numbuffers = config_params.min_numbuffers; + + /* Set buffer size to min buffers size if invalid buffer size is + * given */ + if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]) + ch2_bufsize = + config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]; + if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]) + ch3_bufsize = + config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]; + + config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers; + + if (ch2_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] = + ch2_bufsize; + } + config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers; + + if (ch3_numbuffers) { + config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] = + ch3_bufsize; + } + + /* Allocate memory for six channel objects */ + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + vpif_obj.dev[i] = + kmalloc(sizeof(struct channel_obj), GFP_KERNEL); + /* If memory allocation fails, return error */ + if (!vpif_obj.dev[i]) { + free_channel_objects_index = i; + err = -ENOMEM; + goto vpif_init_free_channel_objects; + } + } + + free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES; + free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS; + free_buffer_index = config_params.numbuffers[i - 1]; + + return 0; + +vpif_init_free_channel_objects: + for (j = 0; j < free_channel_objects_index; j++) + kfree(vpif_obj.dev[j]); + return err; +} + +/* + * vpif_probe: This function creates device entries by register itself to the + * V4L2 driver and initializes fields of each channel objects + */ +static __init int vpif_probe(struct platform_device *pdev) +{ + struct vpif_subdev_info *subdevdata; + struct vpif_display_config *config; + int i, j = 0, k, q, m, err = 0; + struct i2c_adapter *i2c_adap; + struct common_obj *common; + struct channel_obj *ch; + struct video_device *vfd; + struct resource *res; + int subdev_count; + + vpif_dev = &pdev->dev; + + err = initialize_vpif(); + + if (err) { + v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); + return err; + } + + err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); + if (err) { + v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); + return err; + } + + k = 0; + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + for (i = res->start; i <= res->end; i++) { + if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, + "DM646x_Display", + (void *)(&vpif_obj.dev[k]->channel_id))) { + err = -EBUSY; + goto vpif_int_err; + } + } + k++; + } + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + + /* Allocate memory for video device */ + vfd = video_device_alloc(); + if (vfd == NULL) { + for (j = 0; j < i; j++) { + ch = vpif_obj.dev[j]; + video_device_release(ch->video_dev); + } + err = -ENOMEM; + goto vpif_int_err; + } + + /* Initialize field of video device */ + *vfd = vpif_video_template; + vfd->v4l2_dev = &vpif_obj.v4l2_dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), + "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d", + (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff, + (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff, + (VPIF_DISPLAY_VERSION_CODE) & 0xff); + + /* Set video_dev to the video device */ + ch->video_dev = vfd; + } + + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + /* Initialize field of the channel objects */ + atomic_set(&ch->usrs, 0); + for (k = 0; k < VPIF_NUMOBJECTS; k++) { + ch->common[k].numbuffers = 0; + common = &ch->common[k]; + common->io_usrs = 0; + common->started = 0; + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + common->numbuffers = 0; + common->set_addr = NULL; + common->ytop_off = common->ybtm_off = 0; + common->ctop_off = common->cbtm_off = 0; + common->cur_frm = common->next_frm = NULL; + memset(&common->fmt, 0, sizeof(common->fmt)); + common->numbuffers = config_params.numbuffers[k]; + + } + ch->initialized = 0; + ch->channel_id = j; + if (j < 2) + ch->common[VPIF_VIDEO_INDEX].numbuffers = + config_params.numbuffers[ch->channel_id]; + else + ch->common[VPIF_VIDEO_INDEX].numbuffers = 0; + + memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); + + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + ch->common[VPIF_VIDEO_INDEX].fmt.type = + V4L2_BUF_TYPE_VIDEO_OUTPUT; + + /* register video device */ + vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", + (int)ch, (int)&ch->video_dev); + + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 3 : 2)); + if (err < 0) + goto probe_out; + + video_set_drvdata(ch->video_dev, ch); + } + + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + subdev_count = config->subdev_count; + subdevdata = config->subdevinfo; + vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto probe_out; + } + + for (i = 0; i < subdev_count; i++) { + vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, subdevdata[i].name, + &subdevdata[i].board_info, + NULL); + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + + return 0; + +probe_subdev_out: + kfree(vpif_obj.sd); +probe_out: + for (k = 0; k < j; k++) { + ch = vpif_obj.dev[k]; + video_unregister_device(ch->video_dev); + video_device_release(ch->video_dev); + ch->video_dev = NULL; + } +vpif_int_err: + v4l2_device_unregister(&vpif_obj.v4l2_dev); + vpif_err("VPIF IRQ request failed\n"); + for (q = k; k >= 0; k--) { + for (m = i; m >= res->start; m--) + free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); + res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); + m = res->end; + } + + return err; +} + +/* + * vpif_remove: It un-register channels from V4L2 driver + */ +static int vpif_remove(struct platform_device *device) +{ + struct channel_obj *ch; + int i; + + v4l2_device_unregister(&vpif_obj.v4l2_dev); + + /* un-register device */ + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + /* Unregister video device */ + video_unregister_device(ch->video_dev); + + ch->video_dev = NULL; + } + + return 0; +} + +static struct platform_driver vpif_driver = { + .driver = { + .name = "vpif_display", + .owner = THIS_MODULE, + }, + .probe = vpif_probe, + .remove = vpif_remove, +}; + +static __init int vpif_init(void) +{ + return platform_driver_register(&vpif_driver); +} + +/* + * vpif_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 vpif_cleanup(void) +{ + struct platform_device *pdev; + struct resource *res; + int irq_num; + int i = 0; + + pdev = container_of(vpif_dev, struct platform_device, dev); + + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { + for (irq_num = res->start; irq_num <= res->end; irq_num++) + free_irq(irq_num, + (void *)(&vpif_obj.dev[i]->channel_id)); + i++; + } + + platform_driver_unregister(&vpif_driver); + kfree(vpif_obj.sd); + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + +module_init(vpif_init); +module_exit(vpif_cleanup); diff --git a/drivers/media/video/ti-media/vpif_display.h b/drivers/media/video/ti-media/vpif_display.h new file mode 100644 index 0000000..a2a7cd1 --- /dev/null +++ b/drivers/media/video/ti-media/vpif_display.h @@ -0,0 +1,175 @@ +/* + * DM646x display header file + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef DAVINCIHD_DISPLAY_H +#define DAVINCIHD_DISPLAY_H + +/* Header files */ +#include +#include +#include +#include +#include +#include + +#include "vpif.h" + +/* Macros */ +#define VPIF_MAJOR_RELEASE (0) +#define VPIF_MINOR_RELEASE (0) +#define VPIF_BUILD (1) + +#define VPIF_DISPLAY_VERSION_CODE \ + ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD) + +#define VPIF_VALID_FIELD(field) \ + (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ + (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \ + (V4L2_FIELD_SEQ_BT == field))) + +#define VPIF_DISPLAY_MAX_DEVICES (2) +#define VPIF_SLICED_BUF_SIZE (256) +#define VPIF_SLICED_MAX_SERVICES (3) +#define VPIF_VIDEO_INDEX (0) +#define VPIF_VBI_INDEX (1) +#define VPIF_HBI_INDEX (2) + +/* Setting it to 1 as HBI/VBI support yet to be added , else 3*/ +#define VPIF_NUMOBJECTS (1) + +/* Macros */ +#define ISALIGNED(a) (0 == ((a) & 7)) + +/* enumerated data types */ +/* Enumerated data type to give id to each device per channel */ +enum vpif_channel_id { + VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */ + VPIF_CHANNEL3_VIDEO, /* Channel3 Video */ +}; + +/* structures */ + +struct video_obj { + enum v4l2_field buf_field; + u32 latest_only; /* indicate whether to return + * most recent displayed frame only */ + v4l2_std_id stdid; /* Currently selected or default + * standard */ + u32 output_id; /* Current output id */ +}; + +struct vbi_obj { + int num_services; + struct vpif_vbi_params vbiparams; /* vpif parameters for the raw + * vbi data */ +}; + +struct common_obj { + /* Buffer specific parameters */ + u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for + * storing frames */ + u32 numbuffers; /* number of buffers */ + struct videobuf_buffer *cur_frm; /* Pointer pointing to current + * videobuf_buffer */ + struct videobuf_buffer *next_frm; /* Pointer pointing to next + * videobuf_buffer */ + enum v4l2_memory memory; /* This field keeps track of + * type of buffer exchange + * method user has selected */ + struct v4l2_format fmt; /* Used to store the format */ + struct videobuf_queue buffer_queue; /* Buffer queue used in + * video-buf */ + struct list_head dma_queue; /* Queue of filled frames */ + spinlock_t irqlock; /* Used in video-buf */ + + /* channel specific parameters */ + struct mutex lock; /* lock used to access this + * structure */ + u32 io_usrs; /* number of users performing + * IO */ + u8 started; /* Indicates whether streaming + * started */ + u32 ytop_off; /* offset of Y top from the + * starting of the buffer */ + u32 ybtm_off; /* offset of Y bottom from the + * starting of the buffer */ + u32 ctop_off; /* offset of C top from the + * starting of the buffer */ + u32 cbtm_off; /* offset of C bottom from the + * starting of the buffer */ + /* Function pointer to set the addresses */ + void (*set_addr) (unsigned long, unsigned long, + unsigned long, unsigned long); + u32 height; + u32 width; +}; + +struct channel_obj { + /* V4l2 specific parameters */ + struct video_device *video_dev; /* Identifies video device for + * this channel */ + struct v4l2_prio_state prio; /* Used to keep track of state of + * the priority */ + atomic_t usrs; /* number of open instances of + * the channel */ + u32 field_id; /* Indicates id of the field + * which is being displayed */ + u8 initialized; /* flag to indicate whether + * encoder is initialized */ + + enum vpif_channel_id channel_id;/* Identifies channel */ + struct vpif_params vpifparams; + struct common_obj common[VPIF_NUMOBJECTS]; + struct video_obj video; + struct vbi_obj vbi; +}; + +/* File handle structure */ +struct vpif_fh { + struct channel_obj *channel; /* pointer to channel object for + * opened device */ + u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle + * is doing IO */ + enum v4l2_priority prio; /* Used to keep track priority of + * this instance */ + u8 initialized; /* Used to keep track of whether this + * file handle has initialized + * channel or not */ +}; + +/* vpif device structure */ +struct vpif_device { + struct v4l2_device v4l2_dev; + struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS]; + struct v4l2_subdev **sd; + +}; + +struct vpif_config_params { + u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; + u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; + u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; + u8 min_numbuffers; +}; + +/* Struct which keeps track of the line numbers for the sliced vbi service */ +struct vpif_service_line { + u16 service_id; + u16 service_line[2]; + u16 enc_service_id; + u8 bytestowrite; +}; + +#endif /* DAVINCIHD_DISPLAY_H */ diff --git a/drivers/media/video/ti-media/vpss.c b/drivers/media/video/ti-media/vpss.c new file mode 100644 index 0000000..7b281ef --- /dev/null +++ b/drivers/media/video/ti-media/vpss.c @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2009 Texas Instruments. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * common vpss system module platform driver for all video drivers. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VPSS Driver"); +MODULE_AUTHOR("Texas Instruments"); + +/* DM644x defines */ +#define DM644X_SBL_PCR_VPSS (4) + +#define DM355_VPSSBL_INTSEL 0x10 +#define DM355_VPSSBL_EVTSEL 0x14 +/* vpss BL register offsets */ +#define DM355_VPSSBL_CCDCMUX 0x1c +/* vpss CLK register offsets */ +#define DM355_VPSSCLK_CLKCTRL 0x04 +/* masks and shifts */ +#define VPSS_HSSISEL_SHIFT 4 +/* + * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, + * IPIPE_INT1_SDR - vpss_int5 + */ +#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 +/* VENCINT - vpss_int8 */ +#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 + +#define DM365_ISP5_PCCR 0x04 +#define DM365_ISP5_INTSEL1 0x10 +#define DM365_ISP5_INTSEL2 0x14 +#define DM365_ISP5_INTSEL3 0x18 +#define DM365_ISP5_CCDCMUX 0x20 +#define DM365_ISP5_PG_FRAME_SIZE 0x28 +#define DM365_VPBE_CLK_CTRL 0x00 +/* + * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, + * AF - vpss_int3 + */ +#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 +/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ +#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f +/* VENC - vpss_int8 */ +#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 + +/* masks and shifts for DM365*/ +#define DM365_CCDC_PG_VD_POL_SHIFT 0 +#define DM365_CCDC_PG_HD_POL_SHIFT 1 + +#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) +#define CCD_SRC_SEL_SHIFT 4 + +/* Different SoC platforms supported by this driver */ +enum vpss_platform_type { + DM644X, + DM355, + DM365, +}; + +/* + * vpss operations. Depends on platform. Not all functions are available + * on all platforms. The api, first check if a functio is available before + * invoking it. In the probe, the function ptrs are intialized based on + * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. + */ +struct vpss_hw_ops { + /* enable clock */ + int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); + /* select input to ccdc */ + void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); + /* clear wbl overflow bit */ + int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); +}; + +/* vpss configuration */ +struct vpss_oper_config { + __iomem void *vpss_regs_base0; + __iomem void *vpss_regs_base1; + enum vpss_platform_type platform; + spinlock_t vpss_lock; + struct vpss_hw_ops hw_ops; +}; + +static struct vpss_oper_config oper_cfg; + +/* register access routines */ +static inline u32 bl_regr(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); +} + +static inline void bl_regw(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); +} + +static inline u32 vpss_regr(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base1 + offset); +} + +static inline void vpss_regw(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); +} + +/* For DM365 only */ +static inline u32 isp5_read(u32 offset) +{ + return __raw_readl(oper_cfg.vpss_regs_base0 + offset); +} + +/* For DM365 only */ +static inline void isp5_write(u32 val, u32 offset) +{ + __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); +} + +static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; + + /* if we are using pattern generator, enable it */ + if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) + temp |= 0x08; + + temp |= (src_sel << CCD_SRC_SEL_SHIFT); + isp5_write(temp, DM365_ISP5_CCDCMUX); +} + +static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); +} + +int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) +{ + if (!oper_cfg.hw_ops.select_ccdc_source) + return -EINVAL; + + oper_cfg.hw_ops.select_ccdc_source(src_sel); + return 0; +} +EXPORT_SYMBOL(vpss_select_ccdc_source); + +static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) +{ + u32 mask = 1, val; + + if (wbl_sel < VPSS_PCR_AEW_WBL_0 || + wbl_sel > VPSS_PCR_CCDC_WBL_O) + return -EINVAL; + + /* writing a 0 clear the overflow */ + mask = ~(mask << wbl_sel); + val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; + bl_regw(val, DM644X_SBL_PCR_VPSS); + return 0; +} + +int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) +{ + if (!oper_cfg.hw_ops.clear_wbl_overflow) + return -EINVAL; + + return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); +} +EXPORT_SYMBOL(vpss_clear_wbl_overflow); + +/* + * dm355_enable_clock - Enable VPSS Clock + * @clock_sel: CLock to be enabled/disabled + * @en: enable/disable flag + * + * This is called to enable or disable a vpss clock + */ +static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + unsigned long flags; + u32 utemp, mask = 0x1, shift = 0; + + switch (clock_sel) { + case VPSS_VPBE_CLOCK: + /* nothing since lsb */ + break; + case VPSS_VENC_CLOCK_SEL: + shift = 2; + break; + case VPSS_CFALD_CLOCK: + shift = 3; + break; + case VPSS_H3A_CLOCK: + shift = 4; + break; + case VPSS_IPIPE_CLOCK: + shift = 5; + break; + case VPSS_CCDC_CLOCK: + shift = 6; + break; + default: + printk(KERN_ERR "dm355_enable_clock:" + " Invalid selector: %d\n", clock_sel); + return -EINVAL; + } + + spin_lock_irqsave(&oper_cfg.vpss_lock, flags); + utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); + if (!en) + utemp &= ~(mask << shift); + else + utemp |= (mask << shift); + + vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); + spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); + return 0; +} + +static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + unsigned long flags; + u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; + u32 (*read)(u32 offset) = isp5_read; + void(*write)(u32 val, u32 offset) = isp5_write; + + switch (clock_sel) { + case VPSS_BL_CLOCK: + break; + case VPSS_CCDC_CLOCK: + shift = 1; + break; + case VPSS_H3A_CLOCK: + shift = 2; + break; + case VPSS_RSZ_CLOCK: + shift = 3; + break; + case VPSS_IPIPE_CLOCK: + shift = 4; + break; + case VPSS_IPIPEIF_CLOCK: + shift = 5; + break; + case VPSS_PCLK_INTERNAL: + shift = 6; + break; + case VPSS_PSYNC_CLOCK_SEL: + shift = 7; + break; + case VPSS_VPBE_CLOCK: + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_VENC_CLOCK_SEL: + shift = 2; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK: + shift = 3; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_FDIF_CLOCK: + shift = 4; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_OSD_CLOCK_SEL: + shift = 6; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + case VPSS_LDC_CLOCK_SEL: + shift = 7; + read = vpss_regr; + write = vpss_regw; + offset = DM365_VPBE_CLK_CTRL; + break; + default: + printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", + clock_sel); + return -1; + } + + spin_lock_irqsave(&oper_cfg.vpss_lock, flags); + utemp = read(offset); + if (!en) { + mask = ~mask; + utemp &= (mask << shift); + } else + utemp |= (mask << shift); + + write(utemp, offset); + spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); + + return 0; +} + +int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) +{ + if (!oper_cfg.hw_ops.enable_clock) + return -EINVAL; + + return oper_cfg.hw_ops.enable_clock(clock_sel, en); +} +EXPORT_SYMBOL(vpss_enable_clock); + +void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) +{ + int val = 0; + val = isp5_read(DM365_ISP5_CCDCMUX); + + val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); + val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); + + isp5_write(val, DM365_ISP5_CCDCMUX); +} +EXPORT_SYMBOL(dm365_vpss_set_sync_pol); + +void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) +{ + int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; + + current_reg |= (frame_size.pplen - 1); + isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); +} +EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); + +static int __init vpss_probe(struct platform_device *pdev) +{ + struct resource *r1, *r2; + char *platform_name; + int status; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENOENT; + } + + platform_name = pdev->dev.platform_data; + if (!strcmp(platform_name, "dm355_vpss")) + oper_cfg.platform = DM355; + else if (!strcmp(platform_name, "dm365_vpss")) + oper_cfg.platform = DM365; + else if (!strcmp(platform_name, "dm644x_vpss")) + oper_cfg.platform = DM644X; + else { + dev_err(&pdev->dev, "vpss driver not supported on" + " this platform\n"); + return -ENODEV; + } + + dev_info(&pdev->dev, "%s vpss probed\n", platform_name); + r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r1) + return -ENOENT; + + r1 = request_mem_region(r1->start, resource_size(r1), r1->name); + if (!r1) + return -EBUSY; + + oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1)); + if (!oper_cfg.vpss_regs_base0) { + status = -EBUSY; + goto fail1; + } + + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!r2) { + status = -ENOENT; + goto fail2; + } + r2 = request_mem_region(r2->start, resource_size(r2), r2->name); + if (!r2) { + status = -EBUSY; + goto fail2; + } + + oper_cfg.vpss_regs_base1 = ioremap(r2->start, + resource_size(r2)); + if (!oper_cfg.vpss_regs_base1) { + status = -EBUSY; + goto fail3; + } + } + + if (oper_cfg.platform == DM355) { + oper_cfg.hw_ops.enable_clock = dm355_enable_clock; + oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; + /* Setup vpss interrupts */ + bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); + bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); + } else if (oper_cfg.platform == DM365) { + oper_cfg.hw_ops.enable_clock = dm365_enable_clock; + oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; + /* Setup vpss interrupts */ + isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); + isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); + isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); + } else + oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; + + spin_lock_init(&oper_cfg.vpss_lock); + dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); + return 0; + +fail3: + release_mem_region(r2->start, resource_size(r2)); +fail2: + iounmap(oper_cfg.vpss_regs_base0); +fail1: + release_mem_region(r1->start, resource_size(r1)); + return status; +} + +static int __devexit vpss_remove(struct platform_device *pdev) +{ + struct resource *res; + + iounmap(oper_cfg.vpss_regs_base0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { + iounmap(oper_cfg.vpss_regs_base1); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(res->start, resource_size(res)); + } + return 0; +} + +static struct platform_driver vpss_driver = { + .driver = { + .name = "vpss", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(vpss_remove), + .probe = vpss_probe, +}; + +static void vpss_exit(void) +{ + platform_driver_unregister(&vpss_driver); +} + +static int __init vpss_init(void) +{ + return platform_driver_register(&vpss_driver); +} +subsys_initcall(vpss_init); +module_exit(vpss_exit); diff --git a/include/media/davinci/ccdc_types.h b/include/media/davinci/ccdc_types.h deleted file mode 100644 index 5773874..0000000 --- a/include/media/davinci/ccdc_types.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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_TYPES_H -#define _CCDC_TYPES_H -enum ccdc_pixfmt { - CCDC_PIXFMT_RAW, - CCDC_PIXFMT_YCBCR_16BIT, - CCDC_PIXFMT_YCBCR_8BIT -}; - -enum ccdc_frmfmt { - CCDC_FRMFMT_PROGRESSIVE, - CCDC_FRMFMT_INTERLACED -}; - -/* PIXEL ORDER IN MEMORY from LSB to MSB */ -/* only applicable for 8-bit input mode */ -enum ccdc_pixorder { - CCDC_PIXORDER_YCBYCR, - CCDC_PIXORDER_CBYCRY, -}; - -enum ccdc_buftype { - CCDC_BUFTYPE_FLD_INTERLEAVED, - CCDC_BUFTYPE_FLD_SEPARATED -}; -#endif diff --git a/include/media/davinci/dm355_ccdc.h b/include/media/davinci/dm355_ccdc.h deleted file mode 100644 index df8a7b1..0000000 --- a/include/media/davinci/dm355_ccdc.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * 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 _DM355_CCDC_H -#define _DM355_CCDC_H -#include -#include - -/* enum for No of pixel per line to be avg. in Black Clamping */ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gama width */ -enum ccdc_gamma_width { - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_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 { - CCDC_DATA_NO_SHIFT, - CCDC_DATA_SHIFT_1BIT, - CCDC_DATA_SHIFT_2BIT, - CCDC_DATA_SHIFT_3BIT, - CCDC_DATA_SHIFT_4BIT, - CCDC_DATA_SHIFT_5BIT, - CCDC_DATA_SHIFT_6BIT -}; - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; -enum ccdc_mfilt1 { - CCDC_NO_MEDIAN_FILTER1, - CCDC_AVERAGE_FILTER1, - CCDC_MEDIAN_FILTER1 -}; - -enum ccdc_mfilt2 { - CCDC_NO_MEDIAN_FILTER2, - CCDC_AVERAGE_FILTER2, - CCDC_MEDIAN_FILTER2 -}; - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gama Width Input */ - enum ccdc_gamma_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 ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_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 ccdc_black_compensation { - /* Constant value to subtract from Red component */ - unsigned char r; - /* Constant value to subtract from Gr component */ - unsigned char gr; - /* Constant value to subtract from Blue component */ - unsigned char b; - /* Constant value to subtract from Gb component */ - unsigned char gb; -}; - -struct ccdc_float { - int integer; - unsigned int decimal; -}; - -#define CCDC_CSC_COEFF_TABLE_SIZE 16 -/* structure for color space converter */ -struct ccdc_csc { - unsigned char enable; - /* - * S8Q5. Use 2 decimal precision, user values range from -3.00 to 3.99. - * example - to use 1.03, set integer part as 1, and decimal part as 3 - * to use -1.03, set integer part as -1 and decimal part as 3 - */ - struct ccdc_float coeff[CCDC_CSC_COEFF_TABLE_SIZE]; -}; - -/* Structures for Vertical Defect Correction*/ -enum ccdc_vdf_csl { - CCDC_VDF_NORMAL, - CCDC_VDF_HORZ_INTERPOL_SAT, - CCDC_VDF_HORZ_INTERPOL -}; - -enum ccdc_vdf_cuda { - CCDC_VDF_WHOLE_LINE_CORRECT, - CCDC_VDF_UPPER_DISABLE -}; - -enum ccdc_dfc_mwr { - CCDC_DFC_MWR_WRITE_COMPLETE, - CCDC_DFC_WRITE_REG -}; - -enum ccdc_dfc_mrd { - CCDC_DFC_READ_COMPLETE, - CCDC_DFC_READ_REG -}; - -enum ccdc_dfc_ma_rst { - CCDC_DFC_INCR_ADDR, - CCDC_DFC_CLR_ADDR -}; - -enum ccdc_dfc_mclr { - CCDC_DFC_CLEAR_COMPLETE, - CCDC_DFC_CLEAR -}; - -struct ccdc_dft_corr_ctl { - enum ccdc_vdf_csl vdfcsl; - enum ccdc_vdf_cuda vdfcuda; - unsigned int vdflsft; -}; - -struct ccdc_dft_corr_mem_ctl { - enum ccdc_dfc_mwr dfcmwr; - enum ccdc_dfc_mrd dfcmrd; - enum ccdc_dfc_ma_rst dfcmarst; - enum ccdc_dfc_mclr dfcmclr; -}; - -#define CCDC_DFT_TABLE_SIZE 16 -/* - * 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 ccdc_vertical_dft { - unsigned char ver_dft_en; - unsigned char gen_dft_en; - unsigned int saturation_ctl; - struct ccdc_dft_corr_ctl dft_corr_ctl; - struct ccdc_dft_corr_mem_ctl dft_corr_mem_ctl; - int table_size; - unsigned int dft_corr_horz[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_vert[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub1[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub2[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub3[CCDC_DFT_TABLE_SIZE]; -}; - -struct ccdc_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 { - /* data shift to be applied before storing */ - enum ccdc_datasft datasft; - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* median filter for sdram */ - enum ccdc_mfilt1 mfilt1; - enum ccdc_mfilt2 mfilt2; - /* low pass filter enable/disable */ - unsigned char lpf_enable; - /* Threshold of median filter */ - int med_filt_thres; - /* - * horz and vertical data offset. Appliable for defect correction - * and lsc - */ - struct ccdc_data_offset data_offset; - /* 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 ccdc_black_compensation blk_comp; - /* struture for vertical Defect Correction Module Configuration */ - struct ccdc_vertical_dft vertical_dft; - /* structure for color space converter Module Configuration */ - struct ccdc_csc csc; - /* color patters for bayer capture */ - struct ccdc_col_pat col_pat_field0; - struct ccdc_col_pat col_pat_field1; -}; - -#ifdef __KERNEL__ -#include - -#define CCDC_WIN_PAL {0, 0, 720, 576} -#define CCDC_WIN_VGA {0, 0, 640, 480} - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol 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; -}; - -/* 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 v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct ccdc_gain gain; - /* offset */ - unsigned int ccdc_offset; - /* horizontal flip enable */ - unsigned char horz_flip_enable; - /* - * enable to store the image in inverse order in memory - * (bottom to top) - */ - unsigned char image_invert_enable; - /* Configurable part of raw data */ - struct ccdc_config_params_raw config_params; -}; - -#endif -#endif /* DM355_CCDC_H */ diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h deleted file mode 100644 index 3e178eb..0000000 --- a/include/media/davinci/dm644x_ccdc.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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 _DM644X_CCDC_H -#define _DM644X_CCDC_H -#include -#include - -/* enum for No of pixel per line to be avg. in Black Clamping*/ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gama width */ -enum ccdc_gama_width { - CCDC_GAMMA_BITS_15_6, - CCDC_GAMMA_BITS_14_5, - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 -}; - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gama Width Input */ - enum ccdc_gama_width gama_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - unsigned char enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_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 ccdc_black_compensation { - /* Constant value to subtract from Red component */ - char r; - /* Constant value to subtract from Gr component */ - char gr; - /* Constant value to subtract from Blue component */ - char b; - /* Constant value to subtract from Gb component */ - char gb; -}; - -/* structure for fault pixel correction */ -struct ccdc_fault_pixel { - /* Enable or Disable fault pixel correction */ - unsigned char 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 { - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* 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 ccdc_black_compensation blk_comp; - /* Structure for Fault Pixel Module Configuration */ - struct ccdc_fault_pixel fault_pxl; -}; - - -#ifdef __KERNEL__ -#include -/* Define to enable/disable video port */ -#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)} - -/* 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 v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol 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; - /* configurable paramaters */ - struct ccdc_config_params_raw config_params; -}; - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol 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; -}; -#endif -#endif /* _DM644X_CCDC_H */ diff --git a/include/media/davinci/isif.h b/include/media/davinci/isif.h deleted file mode 100644 index b0b74ad..0000000 --- a/include/media/davinci/isif.h +++ /dev/null @@ -1,531 +0,0 @@ -/* - * 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 - * - * isif header file - */ -#ifndef _ISIF_H -#define _ISIF_H - -#include -#include - -/* isif float type S8Q8/U8Q8 */ -struct isif_float_8 { - /* 8 bit integer part */ - __u8 integer; - /* 8 bit decimal part */ - __u8 decimal; -}; - -/* isif float type U16Q16/S16Q16 */ -struct isif_float_16 { - /* 16 bit integer part */ - __u16 integer; - /* 16 bit decimal part */ - __u16 decimal; -}; - -/************************************************************************ - * Vertical Defect Correction parameters - ***********************************************************************/ -/* Defect Correction (DFC) table entry */ -struct isif_vdfc_entry { - /* vertical position of defect */ - __u16 pos_vert; - /* horizontal position of defect */ - __u16 pos_horz; - /* - * Defect level of Vertical line defect position. This is subtracted - * from the data at the defect position - */ - __u8 level_at_pos; - /* - * Defect level of the pixels upper than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_up_pixels; - /* - * Defect level of the pixels lower than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_low_pixels; -}; - -#define ISIF_VDFC_TABLE_SIZE 8 -struct isif_dfc { - /* enable vertical defect correction */ - __u8 en; - /* Defect level subtraction. Just fed through if saturating */ -#define ISIF_VDFC_NORMAL 0 - /* - * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 - * if data saturating - */ -#define ISIF_VDFC_HORZ_INTERPOL_IF_SAT 1 - /* Horizontal interpolation (((i-2)+(i+2))/2) */ -#define ISIF_VDFC_HORZ_INTERPOL 2 - /* one of the vertical defect correction modes above */ - __u8 corr_mode; - /* 0 - whole line corrected, 1 - not pixels upper than the defect */ - __u8 corr_whole_line; -#define ISIF_VDFC_NO_SHIFT 0 -#define ISIF_VDFC_SHIFT_1 1 -#define ISIF_VDFC_SHIFT_2 2 -#define ISIF_VDFC_SHIFT_3 3 -#define ISIF_VDFC_SHIFT_4 4 - /* - * defect level shift value. level_at_pos, level_upper_pos, - * and level_lower_pos can be shifted up by this value. Choose - * one of the values above - */ - __u8 def_level_shift; - /* defect saturation level */ - __u16 def_sat_level; - /* number of vertical defects. Max is ISIF_VDFC_TABLE_SIZE */ - __u16 num_vdefects; - /* VDFC table ptr */ - struct isif_vdfc_entry table[ISIF_VDFC_TABLE_SIZE]; -}; - -struct isif_horz_bclamp { - - /* Horizontal clamp disabled. Only vertical clamp value is subtracted */ -#define ISIF_HORZ_BC_DISABLE 0 - /* - * Horizontal clamp value is calculated and subtracted from image data - * along with vertical clamp value - */ -#define ISIF_HORZ_BC_CLAMP_CALC_ENABLED 1 - /* - * Horizontal clamp value calculated from previous image is subtracted - * from image data along with vertical clamp value. - */ -#define ISIF_HORZ_BC_CLAMP_NOT_UPDATED 2 - /* horizontal clamp mode. One of the values above */ - __u8 mode; - /* - * pixel value limit enable. - * 0 - limit disabled - * 1 - pixel value limited to 1023 - */ - __u8 clamp_pix_limit; - /* Select Most left window for bc calculation */ -#define ISIF_SEL_MOST_LEFT_WIN 0 - /* Select Most right window for bc calculation */ -#define ISIF_SEL_MOST_RIGHT_WIN 1 - /* Select most left or right window for clamp val calculation */ - __u8 base_win_sel_calc; - /* Window count per color for calculation. range 1-32 */ - __u8 win_count_calc; - /* Window start position - horizontal for calculation. 0 - 8191 */ - __u16 win_start_h_calc; - /* Window start position - vertical for calculation 0 - 8191 */ - __u16 win_start_v_calc; -#define ISIF_HORZ_BC_SZ_H_2PIXELS 0 -#define ISIF_HORZ_BC_SZ_H_4PIXELS 1 -#define ISIF_HORZ_BC_SZ_H_8PIXELS 2 -#define ISIF_HORZ_BC_SZ_H_16PIXELS 3 - /* Width of the sample window in pixels for calculation */ - __u8 win_h_sz_calc; -#define ISIF_HORZ_BC_SZ_V_32PIXELS 0 -#define ISIF_HORZ_BC_SZ_V_64PIXELS 1 -#define ISIF_HORZ_BC_SZ_V_128PIXELS 2 -#define ISIF_HORZ_BC_SZ_V_256PIXELS 3 - /* Height of the sample window in pixels for calculation */ - __u8 win_v_sz_calc; -}; - -/************************************************************************ - * Black Clamp parameters - ***********************************************************************/ -struct isif_vert_bclamp { - /* Reset value used is the clamp value calculated */ -#define ISIF_VERT_BC_USE_HORZ_CLAMP_VAL 0 - /* Reset value used is reset_clamp_val configured */ -#define ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL 1 - /* No update, previous image value is used */ -#define ISIF_VERT_BC_NO_UPDATE 2 - /* - * Reset value selector for vertical clamp calculation. Use one of - * the above values - */ - __u8 reset_val_sel; - /* U8Q8. Line average coefficient used in vertical clamp calculation */ - __u8 line_ave_coef; - /* Height of the optical black region for calculation */ - __u16 ob_v_sz_calc; - /* Optical black region start position - horizontal. 0 - 8191 */ - __u16 ob_start_h; - /* Optical black region start position - vertical 0 - 8191 */ - __u16 ob_start_v; -}; - -struct isif_black_clamp { - /* - * This offset value is added irrespective of the clamp enable status. - * S13 - */ - __u16 dc_offset; - /* - * Enable black/digital clamp value to be subtracted from the image data - */ - __u8 en; - /* - * black clamp mode. same/separate clamp for 4 colors - * 0 - disable - same clamp value for all colors - * 1 - clamp value calculated separately for all colors - */ - __u8 bc_mode_color; - /* Vrtical start position for bc subtraction */ - __u16 vert_start_sub; - /* Black clamp for horizontal direction */ - struct isif_horz_bclamp horz; - /* Black clamp for vertical direction */ - struct isif_vert_bclamp vert; -}; - -/************************************************************************* -** Color Space Convertion (CSC) -*************************************************************************/ -#define ISIF_CSC_NUM_COEFF 16 -struct isif_color_space_conv { - /* Enable color space conversion */ - __u8 en; - /* - * csc coeffient table. S8Q5, M00 at index 0, M01 at index 1, and - * so forth - */ - struct isif_float_8 coeff[ISIF_CSC_NUM_COEFF]; -}; - - -/************************************************************************* -** Black Compensation parameters -*************************************************************************/ -struct isif_black_comp { - /* Comp for Red */ - __s8 r_comp; - /* Comp for Gr */ - __s8 gr_comp; - /* Comp for Blue */ - __s8 b_comp; - /* Comp for Gb */ - __s8 gb_comp; -}; - -/************************************************************************* -** Gain parameters -*************************************************************************/ -struct isif_gain { - /* Gain for Red or ye */ - struct isif_float_16 r_ye; - /* Gain for Gr or cy */ - struct isif_float_16 gr_cy; - /* Gain for Gb or g */ - struct isif_float_16 gb_g; - /* Gain for Blue or mg */ - struct isif_float_16 b_mg; -}; - -#define ISIF_LINEAR_TAB_SIZE 192 -/************************************************************************* -** Linearization parameters -*************************************************************************/ -struct isif_linearize { - /* Enable or Disable linearization of data */ - __u8 en; - /* Shift value applied */ - __u8 corr_shft; - /* scale factor applied U11Q10 */ - struct isif_float_16 scale_fact; - /* Size of the linear table */ - __u16 table[ISIF_LINEAR_TAB_SIZE]; -}; - -/* Color patterns */ -#define ISIF_RED 0 -#define ISIF_GREEN_RED 1 -#define ISIF_GREEN_BLUE 2 -#define ISIF_BLUE 3 -struct isif_col_pat { - __u8 olop; - __u8 olep; - __u8 elop; - __u8 elep; -}; - -/************************************************************************* -** Data formatter parameters -*************************************************************************/ -struct isif_fmtplen { - /* - * number of program entries for SET0, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen0; - /* - * number of program entries for SET1, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen1; - /** - * number of program entries for SET2, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen2; - /** - * number of program entries for SET3, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen3; -}; - -struct isif_fmt_cfg { -#define ISIF_SPLIT 0 -#define ISIF_COMBINE 1 - /* Split or combine or line alternate */ - __u8 fmtmode; - /* enable or disable line alternating mode */ - __u8 ln_alter_en; -#define ISIF_1LINE 0 -#define ISIF_2LINES 1 -#define ISIF_3LINES 2 -#define ISIF_4LINES 3 - /* Split/combine line number */ - __u8 lnum; - /* Address increment Range 1 - 16 */ - __u8 addrinc; -}; - -struct isif_fmt_addr_ptr { - /* Initial address */ - __u32 init_addr; - /* output line number */ -#define ISIF_1STLINE 0 -#define ISIF_2NDLINE 1 -#define ISIF_3RDLINE 2 -#define ISIF_4THLINE 3 - __u8 out_line; -}; - -struct isif_fmtpgm_ap { - /* program address pointer */ - __u8 pgm_aptr; - /* program address increment or decrement */ - __u8 pgmupdt; -}; - -struct isif_data_formatter { - /* Enable/Disable data formatter */ - __u8 en; - /* data formatter configuration */ - struct isif_fmt_cfg cfg; - /* Formatter program entries length */ - struct isif_fmtplen plen; - /* first pixel in a line fed to formatter */ - __u16 fmtrlen; - /* HD interval for output line. Only valid when split line */ - __u16 fmthcnt; - /* formatter address pointers */ - struct isif_fmt_addr_ptr fmtaddr_ptr[16]; - /* program enable/disable */ - __u8 pgm_en[32]; - /* program address pointers */ - struct isif_fmtpgm_ap fmtpgm_ap[32]; -}; - -struct isif_df_csc { - /* Color Space Conversion confguration, 0 - csc, 1 - df */ - __u8 df_or_csc; - /* csc configuration valid if df_or_csc is 0 */ - struct isif_color_space_conv csc; - /* data formatter configuration valid if df_or_csc is 1 */ - struct isif_data_formatter df; - /* start pixel in a line at the input */ - __u32 start_pix; - /* number of pixels in input line */ - __u32 num_pixels; - /* start line at the input */ - __u32 start_line; - /* number of lines at the input */ - __u32 num_lines; -}; - -struct isif_gain_offsets_adj { - /* Gain adjustment per color */ - struct isif_gain gain; - /* Offset adjustment */ - __u16 offset; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 gain_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 gain_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 gain_h3a_en; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 offset_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 offset_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 offset_h3a_en; -}; - -struct isif_cul { - /* Horizontal Cull pattern for odd lines */ - __u8 hcpat_odd; - /* Horizontal Cull pattern for even lines */ - __u8 hcpat_even; - /* Vertical Cull pattern */ - __u8 vcpat; - /* Enable or disable lpf. Apply when cull is enabled */ - __u8 en_lpf; -}; - -struct isif_compress { -#define ISIF_ALAW 0 -#define ISIF_DPCM 1 -#define ISIF_NO_COMPRESSION 2 - /* Compression Algorithm used */ - __u8 alg; - /* Choose Predictor1 for DPCM compression */ -#define ISIF_DPCM_PRED1 0 - /* Choose Predictor2 for DPCM compression */ -#define ISIF_DPCM_PRED2 1 - /* Predictor for DPCM compression */ - __u8 pred; -}; - -/* all the stuff in this struct will be provided by userland */ -struct isif_config_params_raw { - /* Linearization parameters for image sensor data input */ - struct isif_linearize linearize; - /* Data formatter or CSC */ - struct isif_df_csc df_csc; - /* Defect Pixel Correction (DFC) confguration */ - struct isif_dfc dfc; - /* Black/Digital Clamp configuration */ - struct isif_black_clamp bclamp; - /* Gain, offset adjustments */ - struct isif_gain_offsets_adj gain_offset; - /* Culling */ - struct isif_cul culling; - /* A-Law and DPCM compression options */ - struct isif_compress compress; - /* horizontal offset for Gain/LSC/DFC */ - __u16 horz_offset; - /* vertical offset for Gain/LSC/DFC */ - __u16 vert_offset; - /* color pattern for field 0 */ - struct isif_col_pat col_pat_field0; - /* color pattern for field 1 */ - struct isif_col_pat col_pat_field1; -#define ISIF_NO_SHIFT 0 -#define ISIF_1BIT_SHIFT 1 -#define ISIF_2BIT_SHIFT 2 -#define ISIF_3BIT_SHIFT 3 -#define ISIF_4BIT_SHIFT 4 -#define ISIF_5BIT_SHIFT 5 -#define ISIF_6BIT_SHIFT 6 - /* Data shift applied before storing to SDRAM */ - __u8 data_shift; - /* enable input test pattern generation */ - __u8 test_pat_gen; -}; - -#ifdef __KERNEL__ -struct isif_ycbcr_config { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* ISIF crop window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* isif pix order. Only used for ycbcr capture */ - enum ccdc_pixorder pix_order; - /* isif buffer type. Only used for ycbcr capture */ - enum ccdc_buftype buf_type; -}; - -/* MSB of image data connected to sensor port */ -enum isif_data_msb { - ISIF_BIT_MSB_15, - ISIF_BIT_MSB_14, - ISIF_BIT_MSB_13, - ISIF_BIT_MSB_12, - ISIF_BIT_MSB_11, - ISIF_BIT_MSB_10, - ISIF_BIT_MSB_9, - ISIF_BIT_MSB_8, - ISIF_BIT_MSB_7 -}; - -enum isif_cfa_pattern { - ISIF_CFA_PAT_MOSAIC, - ISIF_CFA_PAT_STRIPE -}; - -struct isif_params_raw { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* buffer type. Applicable for interlaced mode */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct isif_gain gain; - /* cfa pattern */ - enum isif_cfa_pattern cfa_pat; - /* Data MSB position */ - enum isif_data_msb data_msb; - /* Enable horizontal flip */ - unsigned char horz_flip_en; - /* Enable image invert vertically */ - unsigned char image_invert_en; - - /* all the userland defined stuff*/ - struct isif_config_params_raw config_params; -}; - -enum isif_data_pack { - ISIF_PACK_16BIT, - ISIF_PACK_12BIT, - ISIF_PACK_8BIT -}; - -#define ISIF_WIN_NTSC {0, 0, 720, 480} -#define ISIF_WIN_VGA {0, 0, 640, 480} - -#endif -#endif diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h deleted file mode 100644 index dc0dd5b..0000000 --- a/include/media/davinci/vpfe_capture.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include - -#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 CAPTURE_DRV_NAME "vpfe-capture" - -struct vpfe_pixel_format { - struct v4l2_fmtdesc fmtdesc; - /* bytes per pixel */ - int bpp; -}; - -struct vpfe_std_info { - int active_pixels; - int active_lines; - /* current frame format */ - int frame_format; -}; - -struct vpfe_route { - u32 input; - u32 output; -}; - -struct vpfe_subdev_info { - /* Sub device name */ - char name[32]; - /* Sub device group id */ - int grp_id; - /* Number of inputs supported */ - int num_inputs; - /* inputs available at the sub device */ - struct v4l2_input *inputs; - /* Sub dev routing information for each input */ - struct vpfe_route *routes; - /* check if sub dev supports routing */ - int can_route; - /* ccdc bus/interface configuration */ - struct vpfe_hw_if_param ccdc_if_params; - /* i2c subdevice board info */ - struct i2c_board_info board_info; -}; - -struct vpfe_config { - /* Number of sub devices connected to vpfe */ - int num_subdevs; - /* i2c bus adapter no */ - int i2c_adapter_id; - /* information about each subdev */ - struct vpfe_subdev_info *sub_devs; - /* evm card info */ - char *card_name; - /* ccdc name */ - char *ccdc; - /* vpfe clock */ - struct clk *vpssclk; - struct clk *slaveclk; - /* Function for Clearing the interrupt */ - void (*clr_intr)(int vdint); -}; - -struct vpfe_device { - /* V4l2 specific parameters */ - /* Identifies video device for this channel */ - struct video_device *video_dev; - /* sub devices */ - struct v4l2_subdev **sd; - /* vpfe cfg */ - struct vpfe_config *cfg; - /* V4l2 device */ - struct v4l2_device v4l2_dev; - /* parent device */ - struct device *pdev; - /* 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; - /* current interface type */ - struct vpfe_hw_if_param vpfe_if_params; - /* ptr to currently selected sub device */ - struct vpfe_subdev_info *current_subdev; - /* current input at the sub device */ - int current_input; - /* Keeps track of the information about the standard */ - struct vpfe_std_info std_info; - /* std index into std table */ - int std_index; - /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ - unsigned int ccdc_irq0; - unsigned int ccdc_irq1; - /* number of buffers in fbuffers */ - u32 numbuffers; - /* List of buffer pointers for storing frames */ - u8 *fbuffers[VIDEO_MAX_FRAME]; - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; - /* Pointer pointing to next v4l2_buffer */ - struct videobuf_buffer *next_frm; - /* - * 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; - /* - * used when IMP is chained to store the crop window which - * is different from the image window - */ - struct v4l2_rect crop; - /* 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; - /* IRQ lock for DMA queue */ - spinlock_t dma_queue_lock; - /* 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; -}; - -/* File handle structure */ -struct vpfe_fh { - struct vpfe_device *vpfe_dev; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed; - /* Used to keep track priority of this instance */ - enum v4l2_priority prio; -}; - -struct vpfe_config_params { - u8 min_numbuffers; - u8 numbuffers; - u32 min_bufsize; - u32 device_bufsize; -}; - -#endif /* End of __KERNEL__ */ -/** - * VPFE_CMD_S_CCDC_RAW_PARAMS - EXPERIMENTAL IOCTL to set raw capture params - * This can be used to configure modules such as defect pixel correction, - * color space conversion, culling etc. This is an experimental ioctl that - * will change in future kernels. So use this ioctl with care ! - * TODO: This is to be split into multiple ioctls and also explore the - * possibility of extending the v4l2 api to include this - **/ -#define VPFE_CMD_S_CCDC_RAW_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 1, \ - void *) -#endif /* _DAVINCI_VPFE_H */ diff --git a/include/media/davinci/vpfe_types.h b/include/media/davinci/vpfe_types.h deleted file mode 100644 index 76fb74b..0000000 --- a/include/media/davinci/vpfe_types.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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_pin_pol { - VPFE_PINPOL_POSITIVE, - VPFE_PINPOL_NEGATIVE -}; - -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 -}; - -/* interface description */ -struct vpfe_hw_if_param { - enum vpfe_hw_if_type if_type; - enum vpfe_pin_pol hdpol; - enum vpfe_pin_pol vdpol; -}; - -#endif -#endif diff --git a/include/media/davinci/vpss.h b/include/media/davinci/vpss.h deleted file mode 100644 index c59cc02..0000000 --- a/include/media/davinci/vpss.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 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 - * - * vpss - video processing subsystem module header file. - * - * Include this header file if a driver needs to configure vpss system - * module. It exports a set of library functions for video drivers to - * configure vpss system module functions such as clock enable/disable, - * vpss interrupt mux to arm, and other common vpss system module - * functions. - */ -#ifndef _VPSS_H -#define _VPSS_H - -/* selector for ccdc input selection on DM355 */ -enum vpss_ccdc_source_sel { - VPSS_CCDCIN, - VPSS_HSSIIN, - VPSS_PGLPBK, /* for DM365 only */ - VPSS_CCDCPG /* for DM365 only */ -}; - -struct vpss_sync_pol { - unsigned int ccdpg_hdpol:1; - unsigned int ccdpg_vdpol:1; -}; - -struct vpss_pg_frame_size { - short hlpfr; - short pplen; -}; - -/* Used for enable/diable VPSS Clock */ -enum vpss_clock_sel { - /* DM355/DM365 */ - VPSS_CCDC_CLOCK, - VPSS_IPIPE_CLOCK, - VPSS_H3A_CLOCK, - VPSS_CFALD_CLOCK, - /* - * When using VPSS_VENC_CLOCK_SEL in vpss_enable_clock() api - * following applies:- - * en = 0 selects ENC_CLK - * en = 1 selects ENC_CLK/2 - */ - VPSS_VENC_CLOCK_SEL, - VPSS_VPBE_CLOCK, - /* DM365 only clocks */ - VPSS_IPIPEIF_CLOCK, - VPSS_RSZ_CLOCK, - VPSS_BL_CLOCK, - /* - * When using VPSS_PCLK_INTERNAL in vpss_enable_clock() api - * following applies:- - * en = 0 disable internal PCLK - * en = 1 enables internal PCLK - */ - VPSS_PCLK_INTERNAL, - /* - * When using VPSS_PSYNC_CLOCK_SEL in vpss_enable_clock() api - * following applies:- - * en = 0 enables MMR clock - * en = 1 enables VPSS clock - */ - VPSS_PSYNC_CLOCK_SEL, - VPSS_LDC_CLOCK_SEL, - VPSS_OSD_CLOCK_SEL, - VPSS_FDIF_CLOCK, - VPSS_LDC_CLOCK -}; - -/* select input to ccdc on dm355 */ -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel); -/* enable/disable a vpss clock, 0 - success, -1 - failure */ -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en); -/* set sync polarity, only for DM365*/ -void dm365_vpss_set_sync_pol(struct vpss_sync_pol); -/* set the PG_FRAME_SIZE register, only for DM365 */ -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size); - -/* wbl reset for dm644x */ -enum vpss_wbl_sel { - VPSS_PCR_AEW_WBL_0 = 16, - VPSS_PCR_AF_WBL_0, - VPSS_PCR_RSZ4_WBL_0, - VPSS_PCR_RSZ3_WBL_0, - VPSS_PCR_RSZ2_WBL_0, - VPSS_PCR_RSZ1_WBL_0, - VPSS_PCR_PREV_WBL_0, - VPSS_PCR_CCDC_WBL_O, -}; -/* clear wbl overflow flag for DM6446 */ -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel); -#endif diff --git a/include/media/ti-media/ccdc_types.h b/include/media/ti-media/ccdc_types.h new file mode 100644 index 0000000..5773874 --- /dev/null +++ b/include/media/ti-media/ccdc_types.h @@ -0,0 +1,43 @@ +/* + * 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_TYPES_H +#define _CCDC_TYPES_H +enum ccdc_pixfmt { + CCDC_PIXFMT_RAW, + CCDC_PIXFMT_YCBCR_16BIT, + CCDC_PIXFMT_YCBCR_8BIT +}; + +enum ccdc_frmfmt { + CCDC_FRMFMT_PROGRESSIVE, + CCDC_FRMFMT_INTERLACED +}; + +/* PIXEL ORDER IN MEMORY from LSB to MSB */ +/* only applicable for 8-bit input mode */ +enum ccdc_pixorder { + CCDC_PIXORDER_YCBYCR, + CCDC_PIXORDER_CBYCRY, +}; + +enum ccdc_buftype { + CCDC_BUFTYPE_FLD_INTERLEAVED, + CCDC_BUFTYPE_FLD_SEPARATED +}; +#endif diff --git a/include/media/ti-media/dm355_ccdc.h b/include/media/ti-media/dm355_ccdc.h new file mode 100644 index 0000000..0479cdc --- /dev/null +++ b/include/media/ti-media/dm355_ccdc.h @@ -0,0 +1,321 @@ +/* + * 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 _DM355_CCDC_H +#define _DM355_CCDC_H +#include +#include + +/* enum for No of pixel per line to be avg. in Black Clamping */ +enum ccdc_sample_length { + CCDC_SAMPLE_1PIXELS, + CCDC_SAMPLE_2PIXELS, + CCDC_SAMPLE_4PIXELS, + CCDC_SAMPLE_8PIXELS, + CCDC_SAMPLE_16PIXELS +}; + +/* enum for No of lines in Black Clamping */ +enum ccdc_sample_line { + CCDC_SAMPLE_1LINES, + CCDC_SAMPLE_2LINES, + CCDC_SAMPLE_4LINES, + CCDC_SAMPLE_8LINES, + CCDC_SAMPLE_16LINES +}; + +/* enum for Alaw gama width */ +enum ccdc_gamma_width { + CCDC_GAMMA_BITS_13_4, + CCDC_GAMMA_BITS_12_3, + CCDC_GAMMA_BITS_11_2, + CCDC_GAMMA_BITS_10_1, + CCDC_GAMMA_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 { + CCDC_DATA_NO_SHIFT, + CCDC_DATA_SHIFT_1BIT, + CCDC_DATA_SHIFT_2BIT, + CCDC_DATA_SHIFT_3BIT, + CCDC_DATA_SHIFT_4BIT, + CCDC_DATA_SHIFT_5BIT, + CCDC_DATA_SHIFT_6BIT +}; + +enum ccdc_data_size { + CCDC_DATA_16BITS, + CCDC_DATA_15BITS, + CCDC_DATA_14BITS, + CCDC_DATA_13BITS, + CCDC_DATA_12BITS, + CCDC_DATA_11BITS, + CCDC_DATA_10BITS, + CCDC_DATA_8BITS +}; +enum ccdc_mfilt1 { + CCDC_NO_MEDIAN_FILTER1, + CCDC_AVERAGE_FILTER1, + CCDC_MEDIAN_FILTER1 +}; + +enum ccdc_mfilt2 { + CCDC_NO_MEDIAN_FILTER2, + CCDC_AVERAGE_FILTER2, + CCDC_MEDIAN_FILTER2 +}; + +/* structure for ALaw */ +struct ccdc_a_law { + /* Enable/disable A-Law */ + unsigned char enable; + /* Gama Width Input */ + enum ccdc_gamma_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 ccdc_sample_length sample_pixel; + /* only if bClampEnable is TRUE */ + enum ccdc_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 ccdc_black_compensation { + /* Constant value to subtract from Red component */ + unsigned char r; + /* Constant value to subtract from Gr component */ + unsigned char gr; + /* Constant value to subtract from Blue component */ + unsigned char b; + /* Constant value to subtract from Gb component */ + unsigned char gb; +}; + +struct ccdc_float { + int integer; + unsigned int decimal; +}; + +#define CCDC_CSC_COEFF_TABLE_SIZE 16 +/* structure for color space converter */ +struct ccdc_csc { + unsigned char enable; + /* + * S8Q5. Use 2 decimal precision, user values range from -3.00 to 3.99. + * example - to use 1.03, set integer part as 1, and decimal part as 3 + * to use -1.03, set integer part as -1 and decimal part as 3 + */ + struct ccdc_float coeff[CCDC_CSC_COEFF_TABLE_SIZE]; +}; + +/* Structures for Vertical Defect Correction*/ +enum ccdc_vdf_csl { + CCDC_VDF_NORMAL, + CCDC_VDF_HORZ_INTERPOL_SAT, + CCDC_VDF_HORZ_INTERPOL +}; + +enum ccdc_vdf_cuda { + CCDC_VDF_WHOLE_LINE_CORRECT, + CCDC_VDF_UPPER_DISABLE +}; + +enum ccdc_dfc_mwr { + CCDC_DFC_MWR_WRITE_COMPLETE, + CCDC_DFC_WRITE_REG +}; + +enum ccdc_dfc_mrd { + CCDC_DFC_READ_COMPLETE, + CCDC_DFC_READ_REG +}; + +enum ccdc_dfc_ma_rst { + CCDC_DFC_INCR_ADDR, + CCDC_DFC_CLR_ADDR +}; + +enum ccdc_dfc_mclr { + CCDC_DFC_CLEAR_COMPLETE, + CCDC_DFC_CLEAR +}; + +struct ccdc_dft_corr_ctl { + enum ccdc_vdf_csl vdfcsl; + enum ccdc_vdf_cuda vdfcuda; + unsigned int vdflsft; +}; + +struct ccdc_dft_corr_mem_ctl { + enum ccdc_dfc_mwr dfcmwr; + enum ccdc_dfc_mrd dfcmrd; + enum ccdc_dfc_ma_rst dfcmarst; + enum ccdc_dfc_mclr dfcmclr; +}; + +#define CCDC_DFT_TABLE_SIZE 16 +/* + * 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 ccdc_vertical_dft { + unsigned char ver_dft_en; + unsigned char gen_dft_en; + unsigned int saturation_ctl; + struct ccdc_dft_corr_ctl dft_corr_ctl; + struct ccdc_dft_corr_mem_ctl dft_corr_mem_ctl; + int table_size; + unsigned int dft_corr_horz[CCDC_DFT_TABLE_SIZE]; + unsigned int dft_corr_vert[CCDC_DFT_TABLE_SIZE]; + unsigned int dft_corr_sub1[CCDC_DFT_TABLE_SIZE]; + unsigned int dft_corr_sub2[CCDC_DFT_TABLE_SIZE]; + unsigned int dft_corr_sub3[CCDC_DFT_TABLE_SIZE]; +}; + +struct ccdc_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 { + /* data shift to be applied before storing */ + enum ccdc_datasft datasft; + /* data size value from 8 to 16 bits */ + enum ccdc_data_size data_sz; + /* median filter for sdram */ + enum ccdc_mfilt1 mfilt1; + enum ccdc_mfilt2 mfilt2; + /* low pass filter enable/disable */ + unsigned char lpf_enable; + /* Threshold of median filter */ + int med_filt_thres; + /* + * horz and vertical data offset. Appliable for defect correction + * and lsc + */ + struct ccdc_data_offset data_offset; + /* 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 ccdc_black_compensation blk_comp; + /* struture for vertical Defect Correction Module Configuration */ + struct ccdc_vertical_dft vertical_dft; + /* structure for color space converter Module Configuration */ + struct ccdc_csc csc; + /* color patters for bayer capture */ + struct ccdc_col_pat col_pat_field0; + struct ccdc_col_pat col_pat_field1; +}; + +#ifdef __KERNEL__ +#include + +#define CCDC_WIN_PAL {0, 0, 720, 576} +#define CCDC_WIN_VGA {0, 0, 640, 480} + +struct ccdc_params_ycbcr { + /* pixel format */ + enum ccdc_pixfmt pix_fmt; + /* progressive or interlaced frame */ + enum ccdc_frmfmt frm_fmt; + /* video window */ + struct v4l2_rect win; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol 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; +}; + +/* 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 v4l2_rect win; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol hd_pol; + /* interleaved or separated fields */ + enum ccdc_buftype buf_type; + /* Gain values */ + struct ccdc_gain gain; + /* offset */ + unsigned int ccdc_offset; + /* horizontal flip enable */ + unsigned char horz_flip_enable; + /* + * enable to store the image in inverse order in memory + * (bottom to top) + */ + unsigned char image_invert_enable; + /* Configurable part of raw data */ + struct ccdc_config_params_raw config_params; +}; + +#endif +#endif /* DM355_CCDC_H */ diff --git a/include/media/ti-media/dm644x_ccdc.h b/include/media/ti-media/dm644x_ccdc.h new file mode 100644 index 0000000..0e63d1c --- /dev/null +++ b/include/media/ti-media/dm644x_ccdc.h @@ -0,0 +1,184 @@ +/* + * 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 _DM644X_CCDC_H +#define _DM644X_CCDC_H +#include +#include + +/* enum for No of pixel per line to be avg. in Black Clamping*/ +enum ccdc_sample_length { + CCDC_SAMPLE_1PIXELS, + CCDC_SAMPLE_2PIXELS, + CCDC_SAMPLE_4PIXELS, + CCDC_SAMPLE_8PIXELS, + CCDC_SAMPLE_16PIXELS +}; + +/* enum for No of lines in Black Clamping */ +enum ccdc_sample_line { + CCDC_SAMPLE_1LINES, + CCDC_SAMPLE_2LINES, + CCDC_SAMPLE_4LINES, + CCDC_SAMPLE_8LINES, + CCDC_SAMPLE_16LINES +}; + +/* enum for Alaw gama width */ +enum ccdc_gama_width { + CCDC_GAMMA_BITS_15_6, + CCDC_GAMMA_BITS_14_5, + CCDC_GAMMA_BITS_13_4, + CCDC_GAMMA_BITS_12_3, + CCDC_GAMMA_BITS_11_2, + CCDC_GAMMA_BITS_10_1, + CCDC_GAMMA_BITS_09_0 +}; + +enum ccdc_data_size { + CCDC_DATA_16BITS, + CCDC_DATA_15BITS, + CCDC_DATA_14BITS, + CCDC_DATA_13BITS, + CCDC_DATA_12BITS, + CCDC_DATA_11BITS, + CCDC_DATA_10BITS, + CCDC_DATA_8BITS +}; + +/* structure for ALaw */ +struct ccdc_a_law { + /* Enable/disable A-Law */ + unsigned char enable; + /* Gama Width Input */ + enum ccdc_gama_width gama_wd; +}; + +/* structure for Black Clamping */ +struct ccdc_black_clamp { + unsigned char enable; + /* only if bClampEnable is TRUE */ + enum ccdc_sample_length sample_pixel; + /* only if bClampEnable is TRUE */ + enum ccdc_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 ccdc_black_compensation { + /* Constant value to subtract from Red component */ + char r; + /* Constant value to subtract from Gr component */ + char gr; + /* Constant value to subtract from Blue component */ + char b; + /* Constant value to subtract from Gb component */ + char gb; +}; + +/* structure for fault pixel correction */ +struct ccdc_fault_pixel { + /* Enable or Disable fault pixel correction */ + unsigned char 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 { + /* data size value from 8 to 16 bits */ + enum ccdc_data_size data_sz; + /* 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 ccdc_black_compensation blk_comp; + /* Structure for Fault Pixel Module Configuration */ + struct ccdc_fault_pixel fault_pxl; +}; + + +#ifdef __KERNEL__ +#include +/* Define to enable/disable video port */ +#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)} + +/* 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 v4l2_rect win; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol 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; + /* configurable paramaters */ + struct ccdc_config_params_raw config_params; +}; + +struct ccdc_params_ycbcr { + /* pixel format */ + enum ccdc_pixfmt pix_fmt; + /* progressive or interlaced frame */ + enum ccdc_frmfmt frm_fmt; + /* video window */ + struct v4l2_rect win; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol 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; +}; +#endif +#endif /* _DM644X_CCDC_H */ diff --git a/include/media/ti-media/isif.h b/include/media/ti-media/isif.h new file mode 100644 index 0000000..7bdacea --- /dev/null +++ b/include/media/ti-media/isif.h @@ -0,0 +1,531 @@ +/* + * 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 + * + * isif header file + */ +#ifndef _ISIF_H +#define _ISIF_H + +#include +#include + +/* isif float type S8Q8/U8Q8 */ +struct isif_float_8 { + /* 8 bit integer part */ + __u8 integer; + /* 8 bit decimal part */ + __u8 decimal; +}; + +/* isif float type U16Q16/S16Q16 */ +struct isif_float_16 { + /* 16 bit integer part */ + __u16 integer; + /* 16 bit decimal part */ + __u16 decimal; +}; + +/************************************************************************ + * Vertical Defect Correction parameters + ***********************************************************************/ +/* Defect Correction (DFC) table entry */ +struct isif_vdfc_entry { + /* vertical position of defect */ + __u16 pos_vert; + /* horizontal position of defect */ + __u16 pos_horz; + /* + * Defect level of Vertical line defect position. This is subtracted + * from the data at the defect position + */ + __u8 level_at_pos; + /* + * Defect level of the pixels upper than the vertical line defect. + * This is subtracted from the data + */ + __u8 level_up_pixels; + /* + * Defect level of the pixels lower than the vertical line defect. + * This is subtracted from the data + */ + __u8 level_low_pixels; +}; + +#define ISIF_VDFC_TABLE_SIZE 8 +struct isif_dfc { + /* enable vertical defect correction */ + __u8 en; + /* Defect level subtraction. Just fed through if saturating */ +#define ISIF_VDFC_NORMAL 0 + /* + * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 + * if data saturating + */ +#define ISIF_VDFC_HORZ_INTERPOL_IF_SAT 1 + /* Horizontal interpolation (((i-2)+(i+2))/2) */ +#define ISIF_VDFC_HORZ_INTERPOL 2 + /* one of the vertical defect correction modes above */ + __u8 corr_mode; + /* 0 - whole line corrected, 1 - not pixels upper than the defect */ + __u8 corr_whole_line; +#define ISIF_VDFC_NO_SHIFT 0 +#define ISIF_VDFC_SHIFT_1 1 +#define ISIF_VDFC_SHIFT_2 2 +#define ISIF_VDFC_SHIFT_3 3 +#define ISIF_VDFC_SHIFT_4 4 + /* + * defect level shift value. level_at_pos, level_upper_pos, + * and level_lower_pos can be shifted up by this value. Choose + * one of the values above + */ + __u8 def_level_shift; + /* defect saturation level */ + __u16 def_sat_level; + /* number of vertical defects. Max is ISIF_VDFC_TABLE_SIZE */ + __u16 num_vdefects; + /* VDFC table ptr */ + struct isif_vdfc_entry table[ISIF_VDFC_TABLE_SIZE]; +}; + +struct isif_horz_bclamp { + + /* Horizontal clamp disabled. Only vertical clamp value is subtracted */ +#define ISIF_HORZ_BC_DISABLE 0 + /* + * Horizontal clamp value is calculated and subtracted from image data + * along with vertical clamp value + */ +#define ISIF_HORZ_BC_CLAMP_CALC_ENABLED 1 + /* + * Horizontal clamp value calculated from previous image is subtracted + * from image data along with vertical clamp value. + */ +#define ISIF_HORZ_BC_CLAMP_NOT_UPDATED 2 + /* horizontal clamp mode. One of the values above */ + __u8 mode; + /* + * pixel value limit enable. + * 0 - limit disabled + * 1 - pixel value limited to 1023 + */ + __u8 clamp_pix_limit; + /* Select Most left window for bc calculation */ +#define ISIF_SEL_MOST_LEFT_WIN 0 + /* Select Most right window for bc calculation */ +#define ISIF_SEL_MOST_RIGHT_WIN 1 + /* Select most left or right window for clamp val calculation */ + __u8 base_win_sel_calc; + /* Window count per color for calculation. range 1-32 */ + __u8 win_count_calc; + /* Window start position - horizontal for calculation. 0 - 8191 */ + __u16 win_start_h_calc; + /* Window start position - vertical for calculation 0 - 8191 */ + __u16 win_start_v_calc; +#define ISIF_HORZ_BC_SZ_H_2PIXELS 0 +#define ISIF_HORZ_BC_SZ_H_4PIXELS 1 +#define ISIF_HORZ_BC_SZ_H_8PIXELS 2 +#define ISIF_HORZ_BC_SZ_H_16PIXELS 3 + /* Width of the sample window in pixels for calculation */ + __u8 win_h_sz_calc; +#define ISIF_HORZ_BC_SZ_V_32PIXELS 0 +#define ISIF_HORZ_BC_SZ_V_64PIXELS 1 +#define ISIF_HORZ_BC_SZ_V_128PIXELS 2 +#define ISIF_HORZ_BC_SZ_V_256PIXELS 3 + /* Height of the sample window in pixels for calculation */ + __u8 win_v_sz_calc; +}; + +/************************************************************************ + * Black Clamp parameters + ***********************************************************************/ +struct isif_vert_bclamp { + /* Reset value used is the clamp value calculated */ +#define ISIF_VERT_BC_USE_HORZ_CLAMP_VAL 0 + /* Reset value used is reset_clamp_val configured */ +#define ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL 1 + /* No update, previous image value is used */ +#define ISIF_VERT_BC_NO_UPDATE 2 + /* + * Reset value selector for vertical clamp calculation. Use one of + * the above values + */ + __u8 reset_val_sel; + /* U8Q8. Line average coefficient used in vertical clamp calculation */ + __u8 line_ave_coef; + /* Height of the optical black region for calculation */ + __u16 ob_v_sz_calc; + /* Optical black region start position - horizontal. 0 - 8191 */ + __u16 ob_start_h; + /* Optical black region start position - vertical 0 - 8191 */ + __u16 ob_start_v; +}; + +struct isif_black_clamp { + /* + * This offset value is added irrespective of the clamp enable status. + * S13 + */ + __u16 dc_offset; + /* + * Enable black/digital clamp value to be subtracted from the image data + */ + __u8 en; + /* + * black clamp mode. same/separate clamp for 4 colors + * 0 - disable - same clamp value for all colors + * 1 - clamp value calculated separately for all colors + */ + __u8 bc_mode_color; + /* Vrtical start position for bc subtraction */ + __u16 vert_start_sub; + /* Black clamp for horizontal direction */ + struct isif_horz_bclamp horz; + /* Black clamp for vertical direction */ + struct isif_vert_bclamp vert; +}; + +/************************************************************************* +** Color Space Convertion (CSC) +*************************************************************************/ +#define ISIF_CSC_NUM_COEFF 16 +struct isif_color_space_conv { + /* Enable color space conversion */ + __u8 en; + /* + * csc coeffient table. S8Q5, M00 at index 0, M01 at index 1, and + * so forth + */ + struct isif_float_8 coeff[ISIF_CSC_NUM_COEFF]; +}; + + +/************************************************************************* +** Black Compensation parameters +*************************************************************************/ +struct isif_black_comp { + /* Comp for Red */ + __s8 r_comp; + /* Comp for Gr */ + __s8 gr_comp; + /* Comp for Blue */ + __s8 b_comp; + /* Comp for Gb */ + __s8 gb_comp; +}; + +/************************************************************************* +** Gain parameters +*************************************************************************/ +struct isif_gain { + /* Gain for Red or ye */ + struct isif_float_16 r_ye; + /* Gain for Gr or cy */ + struct isif_float_16 gr_cy; + /* Gain for Gb or g */ + struct isif_float_16 gb_g; + /* Gain for Blue or mg */ + struct isif_float_16 b_mg; +}; + +#define ISIF_LINEAR_TAB_SIZE 192 +/************************************************************************* +** Linearization parameters +*************************************************************************/ +struct isif_linearize { + /* Enable or Disable linearization of data */ + __u8 en; + /* Shift value applied */ + __u8 corr_shft; + /* scale factor applied U11Q10 */ + struct isif_float_16 scale_fact; + /* Size of the linear table */ + __u16 table[ISIF_LINEAR_TAB_SIZE]; +}; + +/* Color patterns */ +#define ISIF_RED 0 +#define ISIF_GREEN_RED 1 +#define ISIF_GREEN_BLUE 2 +#define ISIF_BLUE 3 +struct isif_col_pat { + __u8 olop; + __u8 olep; + __u8 elop; + __u8 elep; +}; + +/************************************************************************* +** Data formatter parameters +*************************************************************************/ +struct isif_fmtplen { + /* + * number of program entries for SET0, range 1 - 16 + * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is + * ISIF_COMBINE + */ + __u16 plen0; + /* + * number of program entries for SET1, range 1 - 16 + * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is + * ISIF_COMBINE + */ + __u16 plen1; + /** + * number of program entries for SET2, range 1 - 16 + * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is + * ISIF_COMBINE + */ + __u16 plen2; + /** + * number of program entries for SET3, range 1 - 16 + * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is + * ISIF_COMBINE + */ + __u16 plen3; +}; + +struct isif_fmt_cfg { +#define ISIF_SPLIT 0 +#define ISIF_COMBINE 1 + /* Split or combine or line alternate */ + __u8 fmtmode; + /* enable or disable line alternating mode */ + __u8 ln_alter_en; +#define ISIF_1LINE 0 +#define ISIF_2LINES 1 +#define ISIF_3LINES 2 +#define ISIF_4LINES 3 + /* Split/combine line number */ + __u8 lnum; + /* Address increment Range 1 - 16 */ + __u8 addrinc; +}; + +struct isif_fmt_addr_ptr { + /* Initial address */ + __u32 init_addr; + /* output line number */ +#define ISIF_1STLINE 0 +#define ISIF_2NDLINE 1 +#define ISIF_3RDLINE 2 +#define ISIF_4THLINE 3 + __u8 out_line; +}; + +struct isif_fmtpgm_ap { + /* program address pointer */ + __u8 pgm_aptr; + /* program address increment or decrement */ + __u8 pgmupdt; +}; + +struct isif_data_formatter { + /* Enable/Disable data formatter */ + __u8 en; + /* data formatter configuration */ + struct isif_fmt_cfg cfg; + /* Formatter program entries length */ + struct isif_fmtplen plen; + /* first pixel in a line fed to formatter */ + __u16 fmtrlen; + /* HD interval for output line. Only valid when split line */ + __u16 fmthcnt; + /* formatter address pointers */ + struct isif_fmt_addr_ptr fmtaddr_ptr[16]; + /* program enable/disable */ + __u8 pgm_en[32]; + /* program address pointers */ + struct isif_fmtpgm_ap fmtpgm_ap[32]; +}; + +struct isif_df_csc { + /* Color Space Conversion confguration, 0 - csc, 1 - df */ + __u8 df_or_csc; + /* csc configuration valid if df_or_csc is 0 */ + struct isif_color_space_conv csc; + /* data formatter configuration valid if df_or_csc is 1 */ + struct isif_data_formatter df; + /* start pixel in a line at the input */ + __u32 start_pix; + /* number of pixels in input line */ + __u32 num_pixels; + /* start line at the input */ + __u32 start_line; + /* number of lines at the input */ + __u32 num_lines; +}; + +struct isif_gain_offsets_adj { + /* Gain adjustment per color */ + struct isif_gain gain; + /* Offset adjustment */ + __u16 offset; + /* Enable or Disable Gain adjustment for SDRAM data */ + __u8 gain_sdram_en; + /* Enable or Disable Gain adjustment for IPIPE data */ + __u8 gain_ipipe_en; + /* Enable or Disable Gain adjustment for H3A data */ + __u8 gain_h3a_en; + /* Enable or Disable Gain adjustment for SDRAM data */ + __u8 offset_sdram_en; + /* Enable or Disable Gain adjustment for IPIPE data */ + __u8 offset_ipipe_en; + /* Enable or Disable Gain adjustment for H3A data */ + __u8 offset_h3a_en; +}; + +struct isif_cul { + /* Horizontal Cull pattern for odd lines */ + __u8 hcpat_odd; + /* Horizontal Cull pattern for even lines */ + __u8 hcpat_even; + /* Vertical Cull pattern */ + __u8 vcpat; + /* Enable or disable lpf. Apply when cull is enabled */ + __u8 en_lpf; +}; + +struct isif_compress { +#define ISIF_ALAW 0 +#define ISIF_DPCM 1 +#define ISIF_NO_COMPRESSION 2 + /* Compression Algorithm used */ + __u8 alg; + /* Choose Predictor1 for DPCM compression */ +#define ISIF_DPCM_PRED1 0 + /* Choose Predictor2 for DPCM compression */ +#define ISIF_DPCM_PRED2 1 + /* Predictor for DPCM compression */ + __u8 pred; +}; + +/* all the stuff in this struct will be provided by userland */ +struct isif_config_params_raw { + /* Linearization parameters for image sensor data input */ + struct isif_linearize linearize; + /* Data formatter or CSC */ + struct isif_df_csc df_csc; + /* Defect Pixel Correction (DFC) confguration */ + struct isif_dfc dfc; + /* Black/Digital Clamp configuration */ + struct isif_black_clamp bclamp; + /* Gain, offset adjustments */ + struct isif_gain_offsets_adj gain_offset; + /* Culling */ + struct isif_cul culling; + /* A-Law and DPCM compression options */ + struct isif_compress compress; + /* horizontal offset for Gain/LSC/DFC */ + __u16 horz_offset; + /* vertical offset for Gain/LSC/DFC */ + __u16 vert_offset; + /* color pattern for field 0 */ + struct isif_col_pat col_pat_field0; + /* color pattern for field 1 */ + struct isif_col_pat col_pat_field1; +#define ISIF_NO_SHIFT 0 +#define ISIF_1BIT_SHIFT 1 +#define ISIF_2BIT_SHIFT 2 +#define ISIF_3BIT_SHIFT 3 +#define ISIF_4BIT_SHIFT 4 +#define ISIF_5BIT_SHIFT 5 +#define ISIF_6BIT_SHIFT 6 + /* Data shift applied before storing to SDRAM */ + __u8 data_shift; + /* enable input test pattern generation */ + __u8 test_pat_gen; +}; + +#ifdef __KERNEL__ +struct isif_ycbcr_config { + /* isif pixel format */ + enum ccdc_pixfmt pix_fmt; + /* isif frame format */ + enum ccdc_frmfmt frm_fmt; + /* ISIF crop window */ + struct v4l2_rect win; + /* field polarity */ + enum vpfe_pin_pol fid_pol; + /* interface VD polarity */ + enum vpfe_pin_pol vd_pol; + /* interface HD polarity */ + enum vpfe_pin_pol hd_pol; + /* isif pix order. Only used for ycbcr capture */ + enum ccdc_pixorder pix_order; + /* isif buffer type. Only used for ycbcr capture */ + enum ccdc_buftype buf_type; +}; + +/* MSB of image data connected to sensor port */ +enum isif_data_msb { + ISIF_BIT_MSB_15, + ISIF_BIT_MSB_14, + ISIF_BIT_MSB_13, + ISIF_BIT_MSB_12, + ISIF_BIT_MSB_11, + ISIF_BIT_MSB_10, + ISIF_BIT_MSB_9, + ISIF_BIT_MSB_8, + ISIF_BIT_MSB_7 +}; + +enum isif_cfa_pattern { + ISIF_CFA_PAT_MOSAIC, + ISIF_CFA_PAT_STRIPE +}; + +struct isif_params_raw { + /* isif pixel format */ + enum ccdc_pixfmt pix_fmt; + /* isif frame format */ + enum ccdc_frmfmt frm_fmt; + /* video window */ + struct v4l2_rect win; + /* field polarity */ + enum vpfe_pin_pol fid_pol; + /* interface VD polarity */ + enum vpfe_pin_pol vd_pol; + /* interface HD polarity */ + enum vpfe_pin_pol hd_pol; + /* buffer type. Applicable for interlaced mode */ + enum ccdc_buftype buf_type; + /* Gain values */ + struct isif_gain gain; + /* cfa pattern */ + enum isif_cfa_pattern cfa_pat; + /* Data MSB position */ + enum isif_data_msb data_msb; + /* Enable horizontal flip */ + unsigned char horz_flip_en; + /* Enable image invert vertically */ + unsigned char image_invert_en; + + /* all the userland defined stuff*/ + struct isif_config_params_raw config_params; +}; + +enum isif_data_pack { + ISIF_PACK_16BIT, + ISIF_PACK_12BIT, + ISIF_PACK_8BIT +}; + +#define ISIF_WIN_NTSC {0, 0, 720, 480} +#define ISIF_WIN_VGA {0, 0, 640, 480} + +#endif +#endif diff --git a/include/media/ti-media/vpfe_capture.h b/include/media/ti-media/vpfe_capture.h new file mode 100644 index 0000000..f0a7b7a --- /dev/null +++ b/include/media/ti-media/vpfe_capture.h @@ -0,0 +1,202 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 CAPTURE_DRV_NAME "vpfe-capture" + +struct vpfe_pixel_format { + struct v4l2_fmtdesc fmtdesc; + /* bytes per pixel */ + int bpp; +}; + +struct vpfe_std_info { + int active_pixels; + int active_lines; + /* current frame format */ + int frame_format; +}; + +struct vpfe_route { + u32 input; + u32 output; +}; + +struct vpfe_subdev_info { + /* Sub device name */ + char name[32]; + /* Sub device group id */ + int grp_id; + /* Number of inputs supported */ + int num_inputs; + /* inputs available at the sub device */ + struct v4l2_input *inputs; + /* Sub dev routing information for each input */ + struct vpfe_route *routes; + /* check if sub dev supports routing */ + int can_route; + /* ccdc bus/interface configuration */ + struct vpfe_hw_if_param ccdc_if_params; + /* i2c subdevice board info */ + struct i2c_board_info board_info; +}; + +struct vpfe_config { + /* Number of sub devices connected to vpfe */ + int num_subdevs; + /* i2c bus adapter no */ + int i2c_adapter_id; + /* information about each subdev */ + struct vpfe_subdev_info *sub_devs; + /* evm card info */ + char *card_name; + /* ccdc name */ + char *ccdc; + /* vpfe clock */ + struct clk *vpssclk; + struct clk *slaveclk; + /* Function for Clearing the interrupt */ + void (*clr_intr)(int vdint); +}; + +struct vpfe_device { + /* V4l2 specific parameters */ + /* Identifies video device for this channel */ + struct video_device *video_dev; + /* sub devices */ + struct v4l2_subdev **sd; + /* vpfe cfg */ + struct vpfe_config *cfg; + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* parent device */ + struct device *pdev; + /* 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; + /* current interface type */ + struct vpfe_hw_if_param vpfe_if_params; + /* ptr to currently selected sub device */ + struct vpfe_subdev_info *current_subdev; + /* current input at the sub device */ + int current_input; + /* Keeps track of the information about the standard */ + struct vpfe_std_info std_info; + /* std index into std table */ + int std_index; + /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ + unsigned int ccdc_irq0; + unsigned int ccdc_irq1; + /* number of buffers in fbuffers */ + u32 numbuffers; + /* List of buffer pointers for storing frames */ + u8 *fbuffers[VIDEO_MAX_FRAME]; + /* Pointer pointing to current v4l2_buffer */ + struct videobuf_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct videobuf_buffer *next_frm; + /* + * 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; + /* + * used when IMP is chained to store the crop window which + * is different from the image window + */ + struct v4l2_rect crop; + /* 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; + /* IRQ lock for DMA queue */ + spinlock_t dma_queue_lock; + /* 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; +}; + +/* File handle structure */ +struct vpfe_fh { + struct vpfe_device *vpfe_dev; + /* Indicates whether this file handle is doing IO */ + u8 io_allowed; + /* Used to keep track priority of this instance */ + enum v4l2_priority prio; +}; + +struct vpfe_config_params { + u8 min_numbuffers; + u8 numbuffers; + u32 min_bufsize; + u32 device_bufsize; +}; + +#endif /* End of __KERNEL__ */ +/** + * VPFE_CMD_S_CCDC_RAW_PARAMS - EXPERIMENTAL IOCTL to set raw capture params + * This can be used to configure modules such as defect pixel correction, + * color space conversion, culling etc. This is an experimental ioctl that + * will change in future kernels. So use this ioctl with care ! + * TODO: This is to be split into multiple ioctls and also explore the + * possibility of extending the v4l2 api to include this + **/ +#define VPFE_CMD_S_CCDC_RAW_PARAMS _IOW('V', BASE_VIDIOC_PRIVATE + 1, \ + void *) +#endif /* _DAVINCI_VPFE_H */ diff --git a/include/media/ti-media/vpfe_types.h b/include/media/ti-media/vpfe_types.h new file mode 100644 index 0000000..76fb74b --- /dev/null +++ b/include/media/ti-media/vpfe_types.h @@ -0,0 +1,51 @@ +/* + * 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_pin_pol { + VPFE_PINPOL_POSITIVE, + VPFE_PINPOL_NEGATIVE +}; + +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 +}; + +/* interface description */ +struct vpfe_hw_if_param { + enum vpfe_hw_if_type if_type; + enum vpfe_pin_pol hdpol; + enum vpfe_pin_pol vdpol; +}; + +#endif +#endif diff --git a/include/media/ti-media/vpss.h b/include/media/ti-media/vpss.h new file mode 100644 index 0000000..c59cc02 --- /dev/null +++ b/include/media/ti-media/vpss.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 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 + * + * vpss - video processing subsystem module header file. + * + * Include this header file if a driver needs to configure vpss system + * module. It exports a set of library functions for video drivers to + * configure vpss system module functions such as clock enable/disable, + * vpss interrupt mux to arm, and other common vpss system module + * functions. + */ +#ifndef _VPSS_H +#define _VPSS_H + +/* selector for ccdc input selection on DM355 */ +enum vpss_ccdc_source_sel { + VPSS_CCDCIN, + VPSS_HSSIIN, + VPSS_PGLPBK, /* for DM365 only */ + VPSS_CCDCPG /* for DM365 only */ +}; + +struct vpss_sync_pol { + unsigned int ccdpg_hdpol:1; + unsigned int ccdpg_vdpol:1; +}; + +struct vpss_pg_frame_size { + short hlpfr; + short pplen; +}; + +/* Used for enable/diable VPSS Clock */ +enum vpss_clock_sel { + /* DM355/DM365 */ + VPSS_CCDC_CLOCK, + VPSS_IPIPE_CLOCK, + VPSS_H3A_CLOCK, + VPSS_CFALD_CLOCK, + /* + * When using VPSS_VENC_CLOCK_SEL in vpss_enable_clock() api + * following applies:- + * en = 0 selects ENC_CLK + * en = 1 selects ENC_CLK/2 + */ + VPSS_VENC_CLOCK_SEL, + VPSS_VPBE_CLOCK, + /* DM365 only clocks */ + VPSS_IPIPEIF_CLOCK, + VPSS_RSZ_CLOCK, + VPSS_BL_CLOCK, + /* + * When using VPSS_PCLK_INTERNAL in vpss_enable_clock() api + * following applies:- + * en = 0 disable internal PCLK + * en = 1 enables internal PCLK + */ + VPSS_PCLK_INTERNAL, + /* + * When using VPSS_PSYNC_CLOCK_SEL in vpss_enable_clock() api + * following applies:- + * en = 0 enables MMR clock + * en = 1 enables VPSS clock + */ + VPSS_PSYNC_CLOCK_SEL, + VPSS_LDC_CLOCK_SEL, + VPSS_OSD_CLOCK_SEL, + VPSS_FDIF_CLOCK, + VPSS_LDC_CLOCK +}; + +/* select input to ccdc on dm355 */ +int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel); +/* enable/disable a vpss clock, 0 - success, -1 - failure */ +int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en); +/* set sync polarity, only for DM365*/ +void dm365_vpss_set_sync_pol(struct vpss_sync_pol); +/* set the PG_FRAME_SIZE register, only for DM365 */ +void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size); + +/* wbl reset for dm644x */ +enum vpss_wbl_sel { + VPSS_PCR_AEW_WBL_0 = 16, + VPSS_PCR_AF_WBL_0, + VPSS_PCR_RSZ4_WBL_0, + VPSS_PCR_RSZ3_WBL_0, + VPSS_PCR_RSZ2_WBL_0, + VPSS_PCR_RSZ1_WBL_0, + VPSS_PCR_PREV_WBL_0, + VPSS_PCR_CCDC_WBL_O, +}; +/* clear wbl overflow flag for DM6446 */ +int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel); +#endif